循环遍历带有索引的字符串的字母

逆向工程 部件 x86
2021-06-14 10:14:52

我有以下代码:

00401163   > 8D15 49634000  LEA EDX,DWORD PTR DS:[406349]            ; see below, 0x406349 is pointing to entered username
00401169   . 52             PUSH EDX                                 ; /String => "myusername"
0040116A   . E8 8D020000    CALL <JMP.&kernel32.lstrlenA>            ; \lstrlenA
0040116F   . 8BE8           MOV EBP,EAX
00401171   . B9 05000000    MOV ECX,5
00401176   . 33F6           XOR ESI,ESI                              ; ESI = 0
00401178   . 33C0           XOR EAX,EAX
0040117A   > 8A0C16         MOV CL,BYTE PTR DS:[ESI+EDX]             ; Why is it pointing to 'y' (2nd letter of username) at 1st run in the loop?
0040117D   . 8AD9           MOV BL,CL
0040117F   . 3298 28634000  XOR BL,BYTE PTR DS:[EAX+406328]
00401185   . 40             INC EAX
00401186   . 83F8 05        CMP EAX,5
00401189   . 881C32         MOV BYTE PTR DS:[EDX+ESI],BL
0040118C   . 8888 27634000  MOV BYTE PTR DS:[EAX+406327],CL
00401192   . 75 02          JNZ SHORT crackme.00401196
00401194   . 33C0           XOR EAX,EAX
00401196   > 46             INC ESI
00401197   . 3BF5           CMP ESI,EBP
00401199   .^72 DF          JB SHORT crackme.0040117A

如您所见,0x406349包含用户名:

00406349  6D 79 75 73 65 72 6E 61 6D 65 00 00 00 00 00 00  myusername......

有一个循环会遍历输入的用户名的字母。我不明白为什么循环中的第一次运行 (at 0x40117A) 包含用户名的第二个字母而不是第一个字母,因为索引 ( ESI) 是0.

你能帮我理解吗?

2个回答

EDX可能已被函数调用更改,请参阅stdcall

寄存器 EAX、ECX 和 EDX 指定用于函数内

EDX在调用 之前/之后使用另一个寄存器,或 push+pop lstrlenA

因为 hanno binder 回答 edx 没有被函数调用 lstrlena 保留

您可以通过在操作之前和发布操作之前检测代码来轻松推断出这些事情,其中​​您的假设不适合实际行为

示例测试代码可能如下所示(在 x64 中,您可能需要一个单独的文件用于内联 asm,但是因为您在 cpp 文件中说的是edx而不是rdx内联 asm 就可以了)

#include <stdio.h>
#include <windows.h>
// the vars are global so they are initialised to zero
int preeax,preebx,preecx,preedx,posteax,postebx,postecx,postedx;
void main (void) {
  printf("does lstrlena change edx ? lets check\n");
__asm {
  mov preeax,eax
  mov preebx,ebx
  mov preecx,ecx
  mov preedx,edx  
}
lstrlenA("does this change edx\n");
__asm {
  mov posteax,eax
  mov postebx,ebx
  mov postecx,ecx
  mov postedx,edx  
}
printf(
"preeax = %08x\tposteax = %08x\npreebx = %08x\tpostebx = %08x\n"
"preecx = %08x\tpostecx = %08x\npreedx = %08x\tpostedx = %08x\n",
preeax,posteax,preebx,postebx,preecx,postecx,preedx,postedx);
}

在编译和运行它

edxlstrlen.exe
lstrlena 会改变 edx 吗?让我们检查
preeax = 00000026 posteax = 00000015
preebx = 7ffd8000 postebx = 7ffd8000
preecx = 00401120 postecx = 7c80be86

preedx = 004166a0 发布x = 004121b9

正如 guntram 评论的那样,确认您可以为 edx 拆卸 lstrlena 和 grep

cdb -c "uf kernel32!lstrlena;q" cdb | grep edx
eax=00191eb4 ebx=7ffdb000 ecx=00000007 edx=00000080 esi=00191f48 edi=00191eb4
7c80be71 8d5001          lea     edx,[eax+1] <-------------
7c80be7b 2bc2            sub     eax,edx

猜猜 eax 指向什么:) 或者这里是剧透,你仍然需要了解 x86 堆栈

cdb -c "uf kernel32!lstrlena;q" cdb | grep的EAX
EAX = 00191eb4 EBX = 7ffd7000 ECX = 00000007 EDX = 00000080 ESI = 00191f48 EDI = 00191eb4
7c80be62 8b4508 MOV EAX,DWORD PTR [EBP + 8]
7c80be65 85c0测试EAX,EAX