"Practical Reverse Engineering" 中的勘误表?

Errata in "Practical Reverse Engineering"?

我刚刚开始阅读 Bruce Dang 等人撰写的 实用逆向工程 一书,对第一章末尾 "walk-through" 的一部分感到困惑.这是代码的相关部分:

65: ...
66: loc_10001d16:
67:     mov eax, [ebp-118h]
68:     mov ecx, [ebp-128h]
69:     jmp short loc_10001d2a (line 73)
70: loc_10001d24:
71:     mov eax, [ebp+0ch]
72:     mov ecx, [ebp+0ch]
73: loc_10001d2a:
74:     cmp eax, ecx
75:     pop esi
76:     jnz short loc_10001D38 (line 82)
77:     xor eax, eax
78:     pop edi
79:     mov esp, ebp
80:     pop ebp
81:     retn 0ch
82: ...

以及作者的评论:

"After the loop exits, execution resumes at line 66. Lines 67–68 save the matching PROCESSENTRY32’s th32ParentProcessID/th32ProcessID in EAX/ECX and continue execution at 73. Notice that Line 66 is also a jump target in line 43. Lines 70–74 read the fdwReason parameter of DllMain (EBP+C) and check whether it is 0 (DLL_PROCESS_DETACH). If it is, the return value is set to 0 and it returns; otherwise, it goes to line 82."

这不是我阅读代码时的解释方式;当然,任何跳转到 loc_10001d24(第 70 行)都会导致函数以 return 值 0 无条件地 终止,而不仅仅是 ebp+0x0c 处的值] 是0? (我假设 poping 进入 esi 不会影响 eflags 寄存器,并且第 76 行中的跳转以第 74 行中 cmp eax, ecx 的结果为条件?)这个也与代码中的早期部分一致,如果各种调用函数 return 的值指示失败,则跳转到 loc_10001d24

此外,我认为从第 66 行开始的部分的要点也是 return 值为 0 if PROCESSENTRY32(之前定义的结构,从位置 ebp-0x130 开始在内存中)具有相等的 th32ParentProcessIDebp-0x118 在内存中)和 th32ProcessIDebp-0x128 在内存中)条目;这个对吗?作者的评论似乎没有表明这一点。

作为一个更笼统的问题,即使只是本书的第 1 章,似乎也有相当多的错别字;有谁知道哪里有收集书中勘误表的网页吗?

是的,ECX 和 EAX 都是从同一个内存位置加载的,所以除非有其他东西指向它并且正在异步更改它,否则 cmp x,x / jne 将永远不会-采取。与浮点数不同,任何可能的整数都等于其自身。

你是对的,pop 不会更改 EFLAGS,根据英特尔的手册:https://www.felixcloutier.com/x86/pop

要检查内存位置是否为零,您可以将其加载到 test eax,eax / jnz
的 reg 中 或 cmp dword ptr [ebp + 0xc], 0 / jne.

(JNE和JNZ是同一条指令,不同的助记符让你表达等号或直接为零的语义,基于ZF根据值本身设置。)


Lines 70–74 read the fdwReason parameter of DllMain (EBP+C) and check whether it is 0 (DLL_PROCESS_DETACH)

这是假的。如果这本书充满了这样的东西,那听起来就不是一本好书。

cmp eax,ecx 仅在从加载 2 个不同值的路径到达时才有意义。 (并且不能为此使用 testx & y != 0 不会告诉你它们是否相等。)这似乎不太可能是真正的编译器输出。

这是完整列表。它是在野发现的恶意软件的一部分:

01:    ; BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
02:                _DllMain@12 proc near                 
03: 55               push    ebp
04: 8B EC            mov     ebp, esp
05: 81 EC 30 01 00+  sub     esp, 130h
06: 57               push    edi
07: 0F 01 4D F8      sidt    fword ptr [ebp-8] 
08: 8B 45 FA         mov     eax, [ebp-6] 
09: 3D 00 F4 03 80   cmp     eax, 8003F400h 
10: 76 10            jbe     short loc_10001C88 (line 18) 
11: 3D 00 74 04 80   cmp     eax, 80047400h
12: 73 09            jnb     short loc_10001C88 (line 18) 
13: 33 C0            xor     eax, eax 
14: 5F               pop     edi 
15: 8B E5            mov     esp, ebp 
16: 5D               pop     ebp 
17: C2 0C 00         retn    0Ch 
18:                loc_10001C88:                         
19: 33 C0            xor     eax, eax 
20: B9 49 00 00 00   mov     ecx, 49h 
21: 8D BD D4 FE FF+  lea     edi, [ebp-12Ch] 
22: C7 85 D0 FE FF+  mov     dword ptr [ebp-130h], 0 
23: 50               push    eax
24: 6A 02            push    2
25: F3 AB            rep stosd 
26: E8 2D 2F 00 00   call    CreateToolhelp32Snapshot
27: 8B F8            mov     edi, eax 
28: 83 FF FF         cmp     edi, 0FFFFFFFFh
29: 75 09            jnz     short loc_10001CB9 (line 35)
30: 33 C0            xor     eax, eax
31: 5F               pop     edi
32: 8B E5            mov     esp, ebp
33: 5D               pop     ebp
34: C2 0C 00         retn    0Ch
35:                loc_10001CB9:
36: 8D 85 D0 FE FF+  lea     eax, [ebp-130h] 
37: 56               push    esi
38: 50               push    eax 
39: 57               push    edi
40: C7 85 D0 FE FF+  mov     dword ptr [ebp-130h], 128h 
41: E8 FF 2E 00 00   call    Process32First
42: 85 C0            test    eax, eax
43: 74 4F            jz      short loc_10001D24 (line 70)
44: 8B 35 C0 50 00+  mov     esi, ds:_stricmp
45: 8D 8D F4 FE FF+  lea     ecx, [ebp-10Ch] 
46: 68 50 7C 00 10   push    10007C50h
47: 51               push    ecx
48: FF D6            call    esi 
49: 83 C4 08         add     esp, 8
50: 85 C0            test    eax, eax
51: 74 26            jz      short loc_10001D16 (line 66)
52:                loc_10001CF0:
53: 8D 95 D0 FE FF+  lea     edx, [ebp-130h]
54: 52               push    edx
55: 57               push    edi 
56: E8 CD 2E 00 00   call    Process32Next
57: 85 C0            test    eax, eax
58: 74 23            jz      short loc_10001D24 (line 70)
59: 8D 85 F4 FE FF+  lea     eax, [ebp-10Ch] 
60: 68 50 7C 00 10   push    10007C50h
61: 50               push    eax 
62: FF D6            call    esi 
63: 83 C4 08         add     esp, 8
64: 85 C0            test    eax, eax
65: 75 DA            jnz     short loc_10001CF0 (line 52)
66:                loc_10001D16: 
67: 8B 85 E8 FE FF+  mov     eax, [ebp-118h] 
68: 8B 8D D8 FE FF+  mov     ecx, [ebp-128h] 
69: EB 06            jmp     short loc_10001D2A (line 73)
70:                loc_10001D24: 
71: 8B 45 0C         mov     eax, [ebp+0Ch] 
72: 8B 4D 0C         mov     ecx, [ebp+0Ch] 
73:                loc_10001D2A: 
74: 3B C1            cmp     eax, ecx
75: 5E               pop     esi
76: 75 09            jnz     short loc_10001D38 (line 82) 
77: 33 C0            xor     eax, eax
78: 5F               pop     edi
79: 8B E5            mov     esp, ebp
80: 5D               pop     ebp
81: C2 0C 00         retn    0Ch
82:                loc_10001D38: 
83: 8B 45 0C         mov     eax, [ebp+0Ch] 
84: 48               dec     eax
85: 75 15            jnz     short loc_10001D53 (line 93) 
86: 6A 00            push    0 
87: 6A 00            push    0 
88: 6A 00            push    0 
89: 68 D0 32 00 10   push    100032D0h 
90: 6A 00            push    0 
91: 6A 00            push    0 
92: FF 15 20 50 00+  call    ds:CreateThread
93:                loc_10001D53: 
94: B8 01 00 00 00   mov     eax, 1
95: 5F               pop     edi
96: 8B E5            mov     esp, ebp
97: 5D               pop     ebp
98: C2 0C 00         retn    0Ch
99:                _DllMain@12 endp

所以第 70-74 行本身没有任何意义,但确实服务于最初的目的 - 如果 Process32First()/Process32Next() returns FALSE 那么代码跳转到这里并最终退出0。 如果找到所需的进程,则 eax/ecx 分别设置为 ParentProcessID/ProcessID,以便函数继续。


无论如何,书中还有第 83-85 行:

...lpStartAddress 为 0x100032D0。该块可以反编译如下:

if (fdwReason == DLL_PROCESS_DETACH) { return FALSE; }
if (fdwReason == DLL_THREAD_ATTACH || fdwReason == DLL_THREAD_DETACH) { return TRUE; }
CreateThread(0, 0, (LPTHREAD_START_ROUTINE) 0x100032D0, 0, 0, 0);
return TRUE;

第 83-85 行实际检查 fdwReason 是否等于 DLL_PROCESS_ATTACH(如果不等于则绕过对 CreateThread 的调用,这很有意义),并且没有特殊情况DLL_PROCESS_DETACH.

我会说这本书确实缺乏适当的结构,书中有些东西是理所当然的,而另一些可能是平凡的东西却被强调了。还是很好的资源。

哦,谁说这很容易。