x86汇编栈内密钥乱码问题:如何提取可读字符串?
分析与解决:从x86汇编栈中提取128位可读密钥
首先直接点出你的核心误区:你提前在pop esi后断下,既没考虑x86的小端序存储特性,也没等程序执行完XOR解密循环,所以看到的是加密且字节序反转的乱码——你的初始思路方向没错,但断点时机和细节没把握对。
乱码的两大原因
1. x86小端序导致字节顺序反转
x86架构是小端序存储:多字节数据的低字节存在低地址,高字节存在高地址。你看到的每个push dword 0xXXXXXXX,实际压入栈的字节顺序是反过来的。比如push dword 0x76767975,拆成单个字节是0x75('u')、0x79('y')、0x76('v')、0x76('v'),栈里实际存储的是u y v v,而不是直接把0x76767975转成字符串。所有push的dword都要反转字节顺序才能得到加密后的原始字节序列。
2. 未执行解密逻辑就断点
看你的汇编源码,pop esi之后的代码是关键解密流程:
mov edi,esi mov edx,edi cld mov ecx,0x80 ; 要处理128字节 mov ebx,0x41 ; 解密密钥是0x41(ASCII 'A') xor eax,eax push eax lodsb ; 从esi取一个字节到eax xor eax,ebx ; 字节异或0x41解密 stosb ; 把解密后的字节存回edi(和esi同地址,原地解密) jnz 0xb7 ; 循环处理完所有128字节
你在pop esi后就断下,这时候程序还没开始解密,栈里全是加密后的原始数据,自然是乱码。
调整流程提取可读字符串的两种方法
方法1:让程序执行完解密循环再断点
最简单的方式是把断点设在解密完成后的位置——也就是汇编里的int3指令处(从你的代码看,这个指令在循环结束后)。
- 先找到
int3的实际地址,用GDB查看:x/1i 0x565560b7+0x10 # 或者直接搜索int3指令 - 设置断点并运行:
break *<int3的实际地址> r - 程序停在
int3时,栈里的内容已经完成解密,直接用x/32s $esp(或者按你需要的长度)查看,就能得到可读的密钥字符串。
方法2:手动解密原始栈数据
如果你不想让程序执行到解密完成,也可以手动计算:
- 反转每个push的dword字节顺序:把所有
push dword 0xXXXXXXX的十六进制值,按字节反转(比如0x76767975 → 0x75797676),然后转成ASCII字符,拼接成加密后的完整字符串。 - 逐字节异或0x41:把加密后的每个字符的ASCII值,和0x41(十进制65)做异或运算。比如加密字符
#(ASCII 35),35 ^ 65 = 100 → 对应字符d;加密字符'(ASCII 39),39 ^ 65 = 96 → 对应字符`,以此类推处理所有字节,就能得到解密后的可读密钥。
内容的提问来源于stack exchange,提问作者3therk1ll
相关产品推荐
相关产品推荐

