吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2035|回复: 1
收起左侧

[C&C++ 原创] 函数调用过程

[复制链接]
古月不傲 发表于 2020-2-23 20:53
本帖最后由 古月不傲 于 2020-2-24 12:24 编辑

随便拖入一个程序到IDA
[C] 纯文本查看 复制代码
#include <stdio.h>
#include <stdlib.h>

#include <Windows.h>

HANDLE hEvent = NULL;

DWORD Thread(LPVOID lpParamter)
{
        SetEvent(hEvent);
        WaitForSingleObject(hEvent, -1);
        
        printf("线程正常执行\n");
        return 0;
}

int main(void)
{
        hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
        HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Thread, NULL, 0, NULL);
        WaitForSingleObject(hThread, -1);
        printf("主线程结束\n");

        system("pause");
        return 0;
}

以WaitForSingleObject这个函数为例
1.首先它调用了Kernel32.dll导出的WaitForSingleObject
2.然后调用了Kernel32.dll导出的WaitForSingleObjectEx
3.接着调用了Ntdll.dll导出的NtWaitForSingleObject
4.接着调用了Ntdll.dll导出的KiFastSystemCall
5.通过快速调用 sysenter:
6.调用ntkrnlpa.exe导出的KiFastCallEntry
7.最终调用NtWaitForSingleObject
硬件方式读取MSR的值 msr.174 = cs  cs + 8 = ss msr.175 = esp msr.176 = eip windbg指令rdmsr wrmsr
构造0环cs ss esp eip 因为是3环进0环嘛 总不能还用3环的堆栈对吧。
[Asm] 纯文本查看 复制代码
kd> dt _KTRAP_FRAME
ntdll!_KTRAP_FRAME
   +0x000 DbgEbp           : Uint4B                        //调试等其他作用
   +0x004 DbgEip           : Uint4B
   +0x008 DbgArgMark       : Uint4B
   +0x00c DbgArgPointer    : Uint4B
   +0x010 TempSegCs        : Uint4B
   +0x014 TempEsp          : Uint4B
   +0x018 Dr0              : Uint4B
   +0x01c Dr1              : Uint4B
   +0x020 Dr2              : Uint4B
   +0x024 Dr3              : Uint4B
   +0x028 Dr6              : Uint4B
   +0x02c Dr7              : Uint4B
   +0x030 SegGs            : Uint4B
   +0x034 SegEs            : Uint4B
   +0x038 SegDs            : Uint4B
   +0x03c Edx              : Uint4B
   +0x040 Ecx              : Uint4B
   +0x044 Eax              : Uint4B
   
   +0x048 PreviousPreviousMode : Uint4B                //windows中非易失性寄存器需要在中断例程中先保存
   +0x04c ExceptionList    : Ptr32 _EXCEPTION_REGISTRATION_RECORD
   +0x050 SegFs            : Uint4B
   +0x054 Edi              : Uint4B
   +0x058 Esi              : Uint4B
   +0x05c Ebx              : Uint4B
   +0x060 Ebp              : Uint4B
   +0x064 ErrCode          : Uint4B
   
   +0x068 Eip              : Uint4B                        //中断发生时,保存被中断的代码段和地址,iret返回到此地址
   +0x06c SegCs            : Uint4B
   +0x070 EFlags           : Uint4B
   +0x074 HardwareEsp      : Uint4B                        //中断发生时,若发生权限切换,则要保存旧的堆栈
   +0x078 HardwareSegSs    : Uint4B
   
   +0x07c V86Es            : Uint4B                        //虚拟8086方式下,交换需要保存段寄存器
   +0x080 V86Ds            : Uint4B
   +0x084 V86Fs            : Uint4B
   +0x088 V86Gs            : Uint4B

但是windows并没有使用msr的esp的值 而是通过kpcr.tss.esp的值构造堆栈 而这个值呢又指向了一个叫做ktrap_frame的结构体 +0x07c V86Es 的位置
所以一切的一切就是构造ktrap_frame结构体 它保存了3环寄存器的信息
现在eip也设置好了 而这个eip的值指向了一个叫做KiFastCallEntry的函数 也就是说任何3环进0环 或者0环调用API都要通过这种方式首先经过KiFastCallEntry
下面来看看这个关键函数到底干了什么
[Asm] 纯文本查看 复制代码
nt!KiFastCallEntry:
80542520 b923000000      mov     ecx,23h					
80542525 6a30            push    30h
80542527 0fa1            pop     fs							//fs = 30
80542529 8ed9            mov     ds,cx						//ds = 23
8054252b 8ec1            mov     es,cx						//es = 23
8054252d 648b0d40000000  mov     ecx,dword ptr fs:[40h]		//ecx = kpcr.TSS			
80542534 8b6104          mov     esp,dword ptr [ecx+4]		//esp = TSS.esp      		TSS.esp->ktrap_frame.V86Es
80542537 6a23            push    23h						//ktrap_frame.HardwareSegSs = 23
80542539 52              push    edx						//ktrap_frame.HardwareEsp = edx     mov     edx,esp
8054253a 9c              pushfd								//ktrap_frame.EFlags = eflag
8054253b 6a02            push    2							//ktrap_frame.SegCs = 2
8054253d 83c208          add     edx,8						//3环第一个参数的地址 		edx + 0 = esp     edx + 4 = 返回地址 
80542540 9d              popfd								//pop eflag = 2
80542541 804c240102      or      byte ptr [esp+1],2			//or ktss.Esp0 + 1, 2
80542546 6a1b            push    1Bh						//ktrap_frame.SegCs = 1Bh
80542548 ff350403dfff    push    dword ptr ds:[0FFDF0304h]	//ktrap_frame.Eip = kuser_shared_data.SystemCallReturn
8054254e 6a00            push    0							//ktrap_frame.ErrCode = 0
80542550 55              push    ebp						//ktrap_frame.Ebp = ebp
80542551 53              push    ebx						//ktrap_frame.Ebx = ebx
80542552 56              push    esi						//ktrap_frame.Esi = esi
80542553 57              push    edi						//ktrap_frame.Edi = edi
80542554 648b1d1c000000  mov     ebx,dword ptr fs:[1Ch]		//ebx = kpcr.SelfPcr
8054255b 6a3b            push    3Bh						//ktrap_frame.SegFs = 3Bh
8054255d 8bb324010000    mov     esi,dword ptr [ebx+124h]	//kprcb.CurrentThread
80542563 ff33            push    dword ptr [ebx]			//ktrap_frame.ExceptionList = kpcr.NtTib.ExceptionList
80542565 c703ffffffff    mov     dword ptr [ebx],0FFFFFFFFh	//kpcr.NtTib.ExceptionList = -1
8054256b 8b6e18          mov     ebp,dword ptr [esi+18h]	//kthread.InitialStack 栈底指针
8054256e 6a01            push    1							//ktrap_frame.PreviousPreviousMode = 1
80542570 83ec48          sub     esp,48h					//指向ktrap_frame.DbgEbp 也就是0x00
80542573 81ed9c020000    sub     ebp,29Ch					//指向ktrap_frame.DbgEbp 也就是0x00
80542579 c6864001000001  mov     byte ptr [esi+140h],1		//kthread.PreviousMode = 1 0代表0环 1代表3环
80542580 3bec            cmp     ebp,esp					//检查栈底是否等于栈顶
80542582 758d            jne     nt!KiFastCallEntry2+0x49 (80542511)
80542584 83652c00        and     dword ptr [ebp+2Ch],0		//and 指向ktrap_frame.Dr7, 0
80542588 f6462cff        test    byte ptr [esi+2Ch],0FFh	//判断kthread.DebugActive是不是-1
8054258c 89ae34010000    mov     dword ptr [esi+134h],ebp	//kthread.TrapFrame = ktrap_frame
80542592 0f8538feffff    jne     nt!Dr_FastCallDrSave (805423d0)//调试状态 跳转 压入dr0 - dr7调试寄存器
80542598 8b5d60          mov     ebx,dword ptr [ebp+60h]	//ebx = ktrap_frame.Ebp	
8054259b 8b7d68          mov     edi,dword ptr [ebp+68h]	//edi = ktrap_frame.Eip
8054259e 89550c          mov     dword ptr [ebp+0Ch],edx	//ktrap_frame.DbgArgPointer = 3环第一个参数的地址
805425a1 c74508000ddbba  mov     dword ptr [ebp+8],0BADB0D00h//ktrap_frame.DbgArgMark = 0BADB0D00h
805425a8 895d00          mov     dword ptr [ebp],ebx		//ktrap_frame.DbgEbp = ktrap_frame.Ebp
805425ab 897d04          mov     dword ptr [ebp+4],edi		//ktrap_frame.DbgEip = ktrap_frame.Eip
805425ae fb              sti								//开启中断
//前面一段都是构造ktrap_frame结构体 也就是为了保存3环的数据
805425af 8bf8            mov     edi,eax					//系统服务号	
805425b1 c1ef08          shr     edi,8						//右移8位
805425b4 83e730          and     edi,30h					//与30		不是0 就是10
805425b7 8bcf            mov     ecx,edi					//ecx = edi
805425b9 03bee0000000    add     edi,dword ptr [esi+0E0h]	//edi = kthread.ServiceTable
																	unsigned int *ServiceTableBase;        // 系统服务表基址
																	unsigned int *ServiceCounterTableBase; // 系统服务表被调用的次数
																	unsigned int NumberOfServices;         // 系统服务表函数个数
																	unsigned char *ParamTableBase;         // 系统服务表函数参数大小 (字节)
805425bf 8bd8            mov     ebx,eax					//ebx = 系统服务号
805425c1 25ff0f0000      and     eax,0FFFh					//系统服务号保留低12位
805425c6 3b4708          cmp     eax,dword ptr [edi+8]		//判断 eax-ServiceTable.NumberOfServices
805425c9 0f8333fdffff    jae     nt!KiBBTUnexpectedRange (80542302)//如果大于等于 跳转
805425cf 83f910          cmp     ecx,10h					//判断ecx 是否 = win32k.sys里面的函数
805425d2 751b            jne     nt!KiFastCallEntry+0xcf (805425ef)不是跳转ntkrnlpa.exe
805425d4 648b0d18000000  mov     ecx,dword ptr fs:[18h]		//ecx = _NT_TIB
805425db 33db            xor     ebx,ebx					//ebx = 0
805425dd 0b99700f0000    or      ebx,dword ptr [ecx+0F70h]
805425e3 740a            je      nt!KiFastCallEntry+0xcf (805425ef)
805425e5 52              push    edx
805425e6 50              push    eax
805425e7 ff1548d75580    call    dword ptr [nt!KeGdiFlushUserBatch (8055d748)]//跳转win32k.sys
805425ed 58              pop     eax
805425ee 5a              pop     edx
805425ef 64ff0538060000  inc     dword ptr fs:[638h]
805425f6 8bf2            mov     esi,edx					//esi = 3环第一个参数的地址
805425f8 8b5f0c          mov     ebx,dword ptr [edi+0Ch]	//ebx = ServiceTable.ParamTableBase
805425fb 33c9            xor     ecx,ecx					//ecx = 0
805425fd 8a0c18          mov     cl,byte ptr [eax+ebx]		//cl  = ParamTableBase[eax] 取参数的字节个数
80542600 8b3f            mov     edi,dword ptr [edi]		//edi = ServiceTable.ServiceTableBase
80542602 8b1c87          mov     ebx,dword ptr [edi+eax*4]	//ebx = ServiceTable.ServiceTableBase[系统服务号]
80542605 2be1            sub     esp,ecx					//提升参数堆栈 cl字节
80542607 c1e902          shr     ecx,2						//ecx右移2位	 rep movs
8054260a 8bfc            mov     edi,esp					//edi = esp
8054260c 3b3534315680    cmp     esi,dword ptr [nt!MmUserProbeAddress (80563134)]//用户参数越界检查
80542612 0f83a8010000    jae     nt!KiSystemCallExit2+0x9f (805427c0)//结束 跳转
80542618 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]//mov [edi], [esi] ecx--
8054261a ffd3            call    ebx						//调用系统服务号的函数

总结 任何3环程序只要调用系统关键函数都要通过以上这种方式一步一步调用 0环直接调用内核模块 以此说明3环约束非常多 相当麻烦。
实验环境xp 有的人问为啥不搞64位 32位都搞不明白 64位不现实的 就这样把。
1.png
2.png

免费评分

参与人数 1威望 +1 吾爱币 +7 热心值 +1 收起 理由
苏紫方璇 + 1 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

weilaikeji007 发表于 2020-2-23 21:26
感谢楼主。已学习
帝王Burlk 发表于 2020-3-11 13:15
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-26 07:22

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表