发新话题
打印

[转载]Win32系统中进程主线程初始化时,ebx为什么指向PEB

[转载]Win32系统中进程主线程初始化时,ebx为什么指向PEB

信息来源:邪恶八进制信息安全团队(www.eviloctal.com

阳光在阅读《脱壳的艺术》,其中阐述某些壳修改程序流程的方法,是使用CreateProcess(CREATE_SUSPENDED)创建新的被挂起的进程,此时其初始化线程上下文中,ebx即为其PEB指针。

于是阳光找我讨论这是为什么。我相信大家在用OD的过程中也早已发现,如果不使用CREATE_SUSPENDED,初始化线程在跑到入口点后,其ebx同样指向PEB结构。

显然,我们必须进入Win32系统新进程创建的过程来找这个真相。由于我们知道初始化线程被创建后(尚未Resume)ebx就已经指向PEB了,所以要不然就是在NtCreateThread过程中,要不然就是在它前面。同时也应该在NtCreatePeb之后。因此我就在这个范围内找寻。

应该说这里我犯了个错误,就是没有详细看CreateProcess的流程,而是使劲往NtCreateThread的内核代码看去,N多函数调用关系看得我眼花,虽然这些内核函数对线程的Context有诸多操作,但是均并不涉及其Ebx。

最后终于回过头来看CreateProcessInternalW在NtCreateThread之前的过程。《Windows Internals 4th》在这里一句话带过了:

Before the thread can be created, it needs a stack and a context in which to run, so these are set up now.

原来是恰恰在NtCreateThread之前,在用户态初始化了新线程的Context,再结合网上其他的文章,终于找到关键函数:kernel32!BaseInitializeContext。

BaseInitializeContext(PCONTEXT Context, // 0x200 bytes
PPEB Peb,
PVOID EntryPoint,
DWORD StackTop,
int Type // union (Process, Thread, Fiber)
);

IDA中看一下这个函数:

.text:7C810443
.text:7C810443 __stdcall BaseInitializeContext(x, x, x, x, x) proc near
.text:7C810443                                         ; CODE XREF: CreateRemoteThread(x,x,x,x,x,x,x)+84 p
.text:7C810443                                         ; CreateProcessInternalW(x,x,x,x,x,x,x,x,x,x,x,x)+690 p
.text:7C810443                                         ; CreateFiberEx(x,x,x,x,x)+82 p
.text:7C810443
.text:7C810443 Context         = dword ptr 8
.text:7C810443 PPeb            = dword ptr 0Ch
.text:7C810443 EntryPoint      = dword ptr 10h
.text:7C810443 StackTop        = dword ptr 14h
.text:7C810443 Type            = dword ptr 18h
.text:7C810443
.text:7C810443 ; FUNCTION CHUNK AT .text:7C81508E SIZE 00000019 BYTES
.text:7C810443 ; FUNCTION CHUNK AT .text:7C82FF86 SIZE 0000000F BYTES
.text:7C810443
.text:7C810443                 mov     edi, edi
.text:7C810445                 push    ebp
.text:7C810446                 mov     ebp, esp
.text:7C810448                 mov     eax, [ebp+Context]
.text:7C81044B                 mov     ecx, [ebp+EntryPoint]
.text:7C81044E                 and     [eax+CONTEXT.SegGs], 0
.text:7C810455                 cmp     [ebp+Type], 1
.text:7C810459                 mov     [eax+CONTEXT.Eax], ecx
.text:7C81045F                 mov     ecx, [ebp+PPeb]
.text:7C810462                 mov     [eax+CONTEXT.Ebx], ecx
.text:7C810468                 push    20h
.text:7C81046A                 pop     ecx
.text:7C81046B                 mov     [eax+CONTEXT.SegEs], ecx
.text:7C810471                 mov     [eax+CONTEXT.SegDs], ecx
.text:7C810477                 mov     [eax+CONTEXT.SegSs], ecx
.text:7C81047D                 mov     ecx, [ebp+StackTop]
.text:7C810480                 mov     [eax+CONTEXT.SegFs], 38h
.text:7C81048A                 mov     [eax+CONTEXT.SegCs], 18h
.text:7C810494                 mov     [eax+CONTEXT.EFlags], 3000h
.text:7C81049E                 mov     [eax+CONTEXT.Esp], ecx
.text:7C8104A4                 jnz     loc_7C81508E
.text:7C8104A4
.text:7C8104AA                 mov     dword ptr [eax+CONTEXT.Eip], offset BaseThreadStartThunk(x,x)
.text:7C8104AA
.text:7C8104B4
.text:7C8104B4 loc_7C8104B4:                           ; CODE XREF: BaseInitializeContext(x,x,x,x,x)+4C5F j
.text:7C8104B4                                         ; BaseInitializeContext(x,x,x,x,x)+1FB4D j
.text:7C8104B4                 add     ecx, 0FFFFFFFCh
.text:7C8104B7                 mov     [eax+CONTEXT.ContextFlags], 10007h
.text:7C8104BD                 mov     [eax+CONTEXT.Esp], ecx
.text:7C8104C3                 pop     ebp
.text:7C8104C4                 retn    14h
.text:7C8104C4
.text:7C8104C4 __stdcall BaseInitializeContext(x, x, x, x, x) endp
.text:7C8104C4

.text:7C81508E
.text:7C81508E loc_7C81508E:                           ; CODE XREF: BaseInitializeContext(x,x,x,x,x)+61 j
.text:7C81508E                 cmp     [ebp+Type], 2
.text:7C815092                 jz      loc_7C82FF86
.text:7C815092
.text:7C815098                 mov     dword ptr [eax+CONTEXT.Eip], offset BaseProcessStartThunk(x,x)
.text:7C8150A2                 jmp     loc_7C8104B4
.text:7C8150A2

.text:7C82FF86
.text:7C82FF86 loc_7C82FF86:                           ; CODE XREF: BaseInitializeContext(x,x,x,x,x)+4C4F j
.text:7C82FF86                 mov     dword ptr [eax+CONTEXT.Eip], offset BaseFiberStart()
.text:7C82FF90                 jmp     loc_7C8104B4
.text:7C82FF90

这个函数就是新线程的线程上下文初始化的关键。下面这两行代码:

.text:7C81045F                 mov     ecx, [ebp+PPeb]
.text:7C810462                 mov     [eax+CONTEXT.Ebx], ecx

将其Ebx指向了PEB。同时这个函数也对几个段选择子进行了初始化,因此诸如为什么Ring3进线程初始化时这几个段选择子总是那样的值的问题,也一并解决了。

因为BaseInitializeContext在CreateRemoteThread中也被调用(CreateThread则又调用了CreateRemoteThread),所以Ring3下用这些常规方式创建的进线程,初始化时都经过这个函数,其线程上下文的相关内容便也保持一致的特点。

Update:

之前的说法还是有点不足之处,BaseInitializeContext的第二个参数,准确地来说应该是PPebOrPParameter。当被CreateProcessInternalW调用时,此处传入的是新进程的PEB指针(由父进程对新进程调用NtQueryInformationProcess得到);当被CreateRemoteThread调用时,这里传入的是CreateRemoteThread的第五个输入参数,也就是lpParameter,也就是为新线程指定的传入参数。

BaseInitializeContext函数将相应CONTEXT结构中的Eip字段指定为BaseProcessStartThunk(新进程创建时CreateProcessInternalW调用的时候)或BaseThreadStartThunk(创建非主线程时,由CreateRemoteThread调用的时候),将Eax字段内容指定为线程入口点,将Ebx字段内容指定为新进程的PEB指针(新进程创建时CreateProcessInternalW调用的时候)或创建远程线程时传给新线程的参数(创建非主线程时,由CreateRemoteThread调用的时候)。


新进程的主线程进入BaseProcessStartThunk后:
xor ebp, ebp
push eax; 线程入口点
push 0
jmp BaseProcessStart

BaseProcessStart之后使用这个push eax时压入栈的线程入口点值来调用入口点函数,当入口点函数返回时,使用其返回值调用ExitThread退出线程:
call     dword ptr [ebp+8] ; 之前压入栈的线程入口点
push     eax              ; 进入主线程入口点时,[esp]的值就是这行指令的地址
call     ExitThread

远程线程进入BaseThreadStartThunk后的行为有点类似,但push的参数中多了一个ebx,即传入参数:
xor ebp, ebp
push ebx; 传入参数
push eax; 线程入口点
push 0
jmp BaseThreadStart

BaseThreadStart之后使用前面压入栈的线程入口点值和传入参数来调用入口点函数,当入口点函数返回时,使用其返回值调用ExitThread退出线程:
push     dword ptr [ebp+0Ch] ; 之前压入栈的传入参数
call     dword ptr [ebp+8] ; 之前压入栈的线程入口点
push     eax              ; 进入远程线程入口点时,[esp]的值就是这行指令的地址
call     ExitThread

另外除了进程和线程这两种类型之外,BaseInitializeContext还会被CreateFiberEx调用,相应的对象称为纤程,我还不知道这个纤程具体是怎么回事。
select girl from Guilin where age='18-20' and bg='beautiful'--

TOP

发新话题