如何将字节数组转换为十六进制字符串用于Android Studio Logcat日志输出
问题背景
现有SMALI代码执行完成后,寄存器v4会存储字符串经过UTF-8编码得到的字节数组。由于Logcat无法直接输出原始字节数组内容,需要将该字节数组转换为十六进制字符串后再用于日志打印。
现有代码如下:
sget-object v5, Lkotlin/text/Charsets;->UTF_8:Ljava/nio/charset/Charset; invoke-static {v4, v2}, Ljava/util/Objects;->requireNonNull(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object; invoke-virtual {v4, v5}, Ljava/lang/String;->getBytes(Ljava/nio/charset/Charset;)[B move-result-object v4
实现方案
核心逻辑
每个byte占用8位,可拆分为两个4位的半字节,每个半字节的取值范围为0-15,将取值依次映射为0123456789ABCDEF对应的字符,拼接所有字符即可得到完整的十六进制字符串。
为避免内联逻辑引发寄存器冲突,优先封装独立的静态工具方法完成转换,直接在现有代码后调用即可。
第一步:新增静态转换工具方法
将以下方法添加到当前修改类的任意位置,方法入参为目标字节数组,返回值为对应的十六进制字符串:
.method public static bytesToHex([B)Ljava/lang/String; .registers 9 # 入参为空时直接返回空字符串 if-eqz p0, :return_empty const-string v0, "0123456789ABCDEF" # 获取字节数组长度 array-length v1, p0 # 每个字节对应2个十六进制字符,提前初始化StringBuilder容量减少扩容开销 mul-int/lit8 v2, v1, 0x2 new-instance v3, Ljava/lang/StringBuilder; invoke-direct {v3, v2}, Ljava/lang/StringBuilder;-><init>(I)V const/4 v4, 0x0 :loop_start if-ge v4, v1, :loop_end # 取出当前遍历的字节 aget-byte v5, p0, v4 # 提取高4位映射对应字符 shr-int/lit8 v6, v5, 0x4 and-int/lit8 v6, v6, 0xf invoke-virtual {v0, v6}, Ljava/lang/String;->charAt(I)C move-result v7 invoke-virtual {v3, v7}, Ljava/lang/StringBuilder;->append(C)Ljava/lang/StringBuilder; # 提取低4位映射对应字符 and-int/lit8 v6, v5, 0xf invoke-virtual {v0, v6}, Ljava/lang/String;->charAt(I)C move-result v7 invoke-virtual {v3, v7}, Ljava/lang/StringBuilder;->append(C)Ljava/lang/StringBuilder; # 循环指针后移 add-int/lit8 v4, v4, 0x1 goto :loop_start :loop_end invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; move-result-object v0 return-object v0 :return_empty const-string v0, "" return-object v0 .end method
第二步:新增转换与日志输出逻辑
在原有代码的最后一行(即move-result-object v4)之后,添加以下代码完成转换并输出到Logcat:
# 调用转换方法,将v4中的字节数组转为十六进制字符串 invoke-static {v4}, L<你当前修改的类的全路径>;->bytesToHex([B)Ljava/lang/String; move-result-object v0 # 调用Android系统日志方法输出,日志tag可自定义修改 const-string v1, "HexDebug" invoke-static {v1, v0}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
注意事项
- 代码中的
<你当前修改的类的全路径>需要替换为实际类路径,例如Lcom/example/app/MainActivity; - 需确认当前所在方法的寄存器声明数量足够,若寄存器不足需调整
.registers声明的数值,避免运行时崩溃 - 新增的调用逻辑中,用于存储hex字符串和日志tag的寄存器,需要选择当前方法后续逻辑不会再用到的空闲寄存器,避免覆盖原有值导致逻辑异常
- 若需要输出小写十六进制字符,将工具方法中的映射字符串
0123456789ABCDEF替换为0123456789abcdef即可
内容的提问来源于stack exchange,提问作者azazazaza
相关产品推荐
相关产品推荐

