“实用逆向工程”中的勘误表?
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行将匹配的
PROCESSENTRY32
的th32ParentProcessID/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? (我假设pop
ing 到esi
不会影响eflags
寄存器,并且第76 行的跳转条件是第74 行cmp eax, ecx
的结果?)这也与前面的部分一致代码,如果各种被调用的函数返回指示失败的值,则跳转到loc_10001d24
。
此外,我认为如果PROCESSENTRY32
(前面定义的结构,从内存中的ebp-0x130
位置开始)等于th32ParentProcessID
(@ 987654340@ 在内存中)和th32ProcessID
(ebp-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 个不同值的路径到达时才有意义。 (并且不能为此使用test
,x & 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开发进阶与项目实战》资源下载和内容勘误