“实用逆向工程”中的勘误表?

Posted

技术标签:

【中文标题】“实用逆向工程”中的勘误表?【英文标题】:Errata in "Practical Reverse Engineering"? 【发布时间】:2020-10-08 00:06:44 【问题描述】:

我刚刚开始阅读 Bruce Dang 等人撰写的 Practical Reverse Engineering 一书,我对第一章末尾的“演练”部分感到困惑。这是代码的相关部分:

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: ...

以及作者的评论:

"循环退出后,在第66行继续执行。第67-68行将匹配的PROCESSENTRY32th32ParentProcessID/th32ProcessID保存在EAX/ECX和 在 73 处继续执行。注意第 66 行也是第 43 行的跳转目标。 第 70-74 行读取 DllMain (EBP+C) 的 fdwReason 参数并检查 是否为 0 (DLL_PROCESS_DETACH)。如果是,则返回值设置为 0 并且 它返回;否则,转到第 82 行。”

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

此外,我认为如果PROCESSENTRY32(前面定义的结构,从内存中的ebp-0x130位置开始)等于th32ParentProcessID(@ 987654340@ 在内存中)和th32ProcessIDebp-0x128 在内存中)条目;它是否正确?作者的评论似乎没有表明这一点。

作为一个更普遍的问题,即使只是本书的第 1 章,似乎也有相当多的错别字;有谁知道任何地方都有从书中收集勘误表的网页?

【问题讨论】:

@PeterCordes 酷,你;我就是这么想的 您可以在出版商的网站上找到一些勘误表,勘误部分:wiley.com/en-us/… 【参考方案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来表达相等或直接为零的语义。)


第70-74行读取DllMain(EBP+C)的fdwReason参数,检查是否为0(DLL_PROCESS_DETACH)

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

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

【讨论】:

【参考方案2】:

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

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() 返回 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 没有特殊情况。

我会说这本书确实缺乏适当的结构,有些东西是书认为理所当然的,而另一些可能是世俗的东西是强调的。还是很好的资源。

哦,谁说这很容易。

【讨论】:

嘿@Assaf Levy,很抱歉迟到了回复!好久没上SO了。非常感谢您的详细回答,非常有帮助。

以上是关于“实用逆向工程”中的勘误表?的主要内容,如果未能解决你的问题,请参考以下文章

《Android App开发进阶与项目实战》资源下载和内容勘误

《Android App开发进阶与项目实战》资源下载和内容勘误

《Android App开发入门与项目实战》资源下载和内容勘误

《Android App开发进阶与项目实战》资源下载和内容勘误

《Android App开发入门与项目实战》资源下载和内容勘误

《Android App开发入门与项目实战》资源下载和内容勘误