原由
今天在看加密解密4关于脱壳部分的过程中,下面这一段代码让我感觉迷惑。

让我感到奇怪的是,为什么这么一段代码可以用来Anti Dump的。
找出答案
在我搜索资料的过程中,发现关于LordPE dump功能的一些事情。我们将一个程序dump下来,有这么几个步骤:
1 2 3
| 1. 在系统中找到目标进程 2. 在进程中确定进程的大小ImageSize 3. 把进程中的数据保存到文件
|
这里有个问题就是ImageSize是怎么获取的。在我们的PE头里的Image_Option_Header里有一个成员叫做SizeOfImage,但是这个成员在加壳程序被修改是很常见的。因此在LordPE中并不是获取这个成员来获取ImageSize的。
在LordPE中,是使用Module32Next来获取进程的基本信息,包括ImageSize。而MODULEENTRY32结构的数据是从哪里来的呢?答案是从PEB进程环境块里获取的。以下是PEB的部分结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| struct _PEB (sizeof=488) +000 byte InheritedAddressSpace +001 byte ReadImageFileExecOptions +002 byte BeingDebugged +003 byte SpareBool +004 void *Mutant +008 void *ImageBaseAddress +00c struct _PEB_LDR_DATA *Ldr +010 struct _RTL_USER_PROCESS_PARAMETERS *ProcessParameters +014 void *SubSystemData +018 void *ProcessHeap +01c void *FastPebLock +020 void *FastPebLockRoutine +024 void *FastPebUnlockRoutine
|
通过偏移0xC,我们可以找到_PEB_LDR_DATA,这是_PEB_LDR_DATA的结构:
1 2 3 4 5 6 7 8 9 10 11 12
| struct _PEB_LDR_DATA { ULONG Length; UCHAR Initialized; VOID* SsHandle; struct _LIST_ENTRY InLoadOrderModuleList; struct _LIST_ENTRY InMemoryOrderModuleList; struct _LIST_ENTRY InInitializationOrderModuleList; VOID* EntryInProgress; UCHAR ShutdownInProgress; VOID* ShutdownThreadId; };
|
该结构的后三个成员是指向LDR_MODULE链表结构中相应的三条双向链表头的指针,分别是按照加载顺序、在内存中的地址顺序和初始化顺序排列的模块信息结构的指针。于是通过它,我们能够访问到LDR_MODULE结构。以下是LDR_MODULE结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| typedef struct _LDR_MODULE { LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; PVOID BaseAddress; PVOID EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; SHORT LoadCount; SHORT TlsIndex; LIST_ENTRY HashTableEntry; ULONG TimeDateStamp; } LDR_MODULE, *PLDR_MODULE;
|
可以看到,在0x20的位置,存放着程序的SizeOfImage。LordPE就是通过这样的方式来获取到程序的ImageSize的,因此我们可以通过上面几条汇编代码,来修改掉这个PEB里的值来对抗LordPE的dump。
1 2 3 4
| mov eax,dword ptr fs:[30h] mov eax,dword ptr ds:[eax+0ch] mov eax,dword ptr ds:[eax+0ch] mov dword ptr [eax+20h],1000h
|
使用LordPE的修正镜像大小功能,即可发现,旧镜像大小Lord PE就是使用上面Module32Next的方法获取到ImageSize的,而新镜像大小则是通过Image_Option_Header来获取到SizeOfImage的。

参考资料
https://bbs.pediy.com/thread-17624.htm