【转帖】一个函数通解WINDOWS原理.

逆向分析NtDLL.dll!RtlUnwind函数 引言:RtlUnwind是Kernel32.dll!_except_handler3中的全局展开函数。7C957A40 ; int __stdcall RtlUnwind(PVOID TargetFrame, PVOID TargetIp, 7C957A40 PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue)7C957A 阅读详情

标 题: 【原创】一个函数通解WINDOWS原理.
作 者: qiyewenjie
时 间: 2010-10-10,19:00:39
链 接: http://bbs.pediy.com/showthread.php?t=121973

PS:感谢qiyewenjie这么详细的分析

这是本人第一篇论文,称不上什么技术论文,都是关于windows xp的一些理论知识。由于学习编程没多久,本篇都是参考网上资料,MSDN,并结合自己的理解写下,本人知识有限,难免会有很多错误和不全面的地方,大牛们勿笑话...,虽然这些东西在网上资料不少,但都不全面,没有系统性的总结windows运行原理。本来说要睡觉的,一时心血来潮,遂执笔写下本篇。算是这段对学习做的总结吧..
本篇并没有详细的介绍windows的的运行原理(太多地方都不懂),但大致已经说明了这个意思.嘿嘿
测试环境:windwos xp sp3
测试语言:C   汇编语言
测试工具:OD    IDA   WINDBG
首先,我们先看一下windows体系结构图
名称:  体系结构图.png
查看次数: 1919
文件大小:  243.1 KB
图看完了,接下来我们来做本篇准备工作,用C语言写一个小程序,很简单的,只需要一个按钮,按钮事件中包含CreateFile函数的调用,编译此程序,放到桌面上,接下来本篇以CreateFile通篇讲述。
 
 
第一部分:从鼠标双击到程序显示:
让我们双击这个程序,开始windows之旅................
当我们鼠标双击的时候,鼠标驱动会产生一个中断(interrupt),鼠标属于硬件设备,这个中断属于硬件中断,驱动程序是通过IoConnectInterrupt链接到给定的中断向量,IoConnectInterrupt原型见下面:
NTSTATUS 
  IoConnectInterrupt(
    OUT PKINTERRUPT  *InterruptObject,   //中断结构指针
    IN PKSERVICE_ROUTINE  ServiceRoutine,//中断服务例程
    IN PVOID  ServiceContext,// 服务上下文
    IN PKSPIN_LOCK  SpinLock  OPTIONAL, //初始化的自旋锁
    IN ULONG  Vector, //中断向量
    IN KIRQL  Irql,//  IRQL等级
    IN KIRQL  SynchronizeIrql, // ISR
      IN KINTERRUPT_MODE    InterruptMode,//中断模式
    IN BOOLEAN  ShareVector,//是否共享
    IN KAFFINITY  ProcessorEnableMask,//代表CPU
      IN BOOLEAN  FloatingSave  //浮点寄存器
);
浮点寄存器FS所选择的段描述项接指向该CPU的KPCR结构,KPCR结构中有个指针IDT,这个指针就指向该CPU的"中断向量描述表"IDT,这是一个以中断向量为下表的结构数组,数组的每个元素都是一"中断描述项",每个中断描述项有8个字节,其中第一个32位字节的低16位和第二个32位字节的高16位合在一起就是指向中断响应程序的指针.
来看一下,鼠标中断向量表,本文只列出鼠标的击键中断和释键中断:
功能号 05H 入口 AL = 05H;
BX = 待测的键(0:测左键;1:测右键) 
作用 得到击键信息 出口 AX = 键状态;
BX = 击键次数;
CX = 最后一击时,鼠标的水平位置
DX = 最后一击时,鼠标的垂直位置 
 
功能号 06H 入口 AL = 06H;
BX = 待测的键(同上) 
作用 得到键释放信息 出口 AX = 键状态;
BX = 释放键的次数;
CX = 最后释放时的水平位置
DX = 最后释放时的垂直位置 
各鼠标的功能是通过在AX寄存器设置功能号来调用,这个鼠标中断产生后,利用INT 33H调用的相关功能会产生一个中断,并向总线发送。总线接收到中断向量后,会发送一个中断指令给CPU,令CPU暂时停止当前的任务并对中断进行响应,串行口RBR寄存器在此取出一个字节的数据,该数据的编码置反映事件中的中断,不同的中断事件导致硬件中断服务程序作出不同的处理,在INT 33h的功能Ch建立列程。入口时,ES:DX指向列程CX中存放一个位模式,设定几种应当调用的例程事件。其模式为:
   位                        置1的含义
   0                        鼠标移动
   1                        按下左按钮
   2                        释放左按钮
   3                        按下右按钮
   4                        释放右按钮
   5                        按下中按钮
   6                        释放中按钮
系统得到这个中断消息,从IDT中找出中断响应程序并发送(send)这个消息[MSG],那么应用程序是哪个呢?呵呵,就是我们的windows外壳(shell)程序,它的主进程是explorer.exe,有关消息(MSG)结构定义如下(参考MSDN):
typedef struct tagMSG
{
    HWND hwnd, //接受消息的窗口句柄
    UINT message, //消息类型
    WPARAM wParam,//消息的第一个参数,依消息类型定
    LPARAM lParam,//消息的第二数,依消息类型定
    DWORD time,//消息发出的时间
    POINT pt //消息发出时鼠标的坐标
} MSG;
发送消息(SendMessage)函数,定义如下(见MSDN):
LRESULT SendMessage(
        HWND hWnd,//接受消息的窗口句柄
        UINT Msg,
        WPARAM wParam,
        LPARAM IParam);
接收消息的窗口句柄,就是我们的桌面句柄,利用一些简单的工具就可以得到该句柄,SPY++就系统向桌面发送消息后,消息会放入桌面窗口过程的消息队列,窗口取回消息(GetMessage),MSDN定义:
BOOL GetMessage(
   LPMSG lpMsg,
   HWND hWnd,
   UINT wMsgFilterMin,//指定被检索的最小消息值的整数
   UINT wMsgFilterMax)  //指定被检索的最大消息的整数
得到这个消息后,应用程序会翻译(Translate)这个消息,函数原型是
BOOL TranslateMessage(CONST MSG*lpMsg);
消息翻译成功后,会分发这个消息,定义如下:
LONG DispatchMessage(CONST MSG*lpmsg);
分发消息的作用是将消息传递给操作系统,然后操作系统去调用应用程序已经注册的回调(callback)函数,也就是说我们在窗体的过程函数中处理消息,在这里,由于要运行程序,所以系统会调用CreateProcess函数,定义如下:
BOOL CreateProcess(
    LPCTSTR lpApplicationName,    //可执行模块的字符串
  LPTSTR lpCommandLine,     //接收的命令行
    LPSECURITY_ATTRIBUTES lpProcessAttributes, //进程SA结构 
  LPSECURITY_ATTRIBUTES lpThreadAttributes,  //线程SA结构
  BOOL bInheritHandles,    //句柄是否可以被继承
   DWORD dwCreationFlags,  //创建标志
   LPVOID lpEnvironment,   //进程环境块
   LPCTSTR lpCurrentDirectory,  //当前目录
   LPSTARTUPINFO lpStartupInfo,  //STARTUPINF结构
  LPPROCESS_INFORMATION lpProcessInformation);//进程信息结构
  调用这个函数,系统将创建一个进程内核对象,并设置初始是用计数为1,进程内核对象不是进程本身,而是操作系统用来管理进程的一个小型数据结构,然后系统会为新进程创建虚拟地址空间,并将可执行文件和所有的必要DLL代码及数据加载到进程的地址空间,然后系统会为引用程序创建第一个线程即主线程,这些初始化工作完整后,那么,这个窗口就显示在了桌面上....
以上部分,大多是摘录资料,只是简单的归纳了一下,没看懂的话,我也是无能为力了,只怪我讲的不好.....接下来:
 
 
第二部分:从按钮单击到函数实现:
单击程序上面那个仅有的控件-按钮(button),下文出现了...
按钮被单击会产生WM_LBUTTONDOWN以及WM_LBUTTONUP,这两个是主要的,这个消息被系统捕获,把这个消息发送给应用程序窗口过程,前面已经列出了消息的结构,究竟什么是消息:windows系统下的编程,消息message的传递是贯穿其始终的。系统为每个应用程序都创建了一个消息队列,这个消息我们可以简单理解为一个有特定意义的整数,windows中定义的消息给初学者的印象似乎是“不计其数”的,常见的一部分消息在winuser.h头文件中定义,接下来应用程序从消息队列中取回消息(GetMessage),前面已经给出定义,翻译消息后,把此消息再次转发给系统,系统通过该消息注册的回调函数决定要做什么回应,在这个程序中,简单的说就是调用一个函数CreateFile,原型如下:
HANDLE CreateFile(
  LPCTSTR lpFileName,          // 文件名或路径
  DWORD dwDesiredAccess,       // 读写权限
  DWORD dwShareMode,           //共享模式
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,  SA安全属性结构
  DWORD dwCreationDisposition,  // 创建标志
  DWORD dwFlagsAndAttributes,  //文件属性
  HANDLE hTemplateFile)    // 处理以GENERIC_READ权限打开的文件
这个函数首先在kernel32.dll导出,但是在32位系统中并没有此函数的存在,实际上存在两个版本,CreateFileA和CreateFileW,这两个函数功能完全一样,只是处理的字符格式不一样,A代表ANSI(ANSI),是一个8位的字符,在c语言中定义为char类型,W代表WIDE(宽)字符,是一种16位的UNICODE字符,定义为WCHAR,我们暂且不管是用A还是W函数,那么应用程序是如何调用CreateFile这个函数呢?接下来,我们就要学一点PE文件知识了,在PE文件中,有一个被称为导入表的结构,这个说明了应用程序需要用的函数名和地址(其实还有很多╯﹏╰,结构定义如下:
typedef struct _IMAGE_IMPORT_BY_NAME
{
   WORD Hint;// 函数输出序号
   BYTE Name1[1];//输出函数名称
} IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME
用一些PE工具可以很方便的查看这些信息,例如CreateFile,用OD反汇编此程序,得到如下一段代码:
0045697D   PUSH 0               ; /hTemplateFile = NULL
0045697F   PUSH 80                    ; |Attributes = NORMAL
00456984   LEA EDX,DWORD PTR SS:[EBP-C]             ; |
00456987   PUSH EDI                                 ; |Mode
00456988   PUSH EDX                                 ; |pSecurity
00456989   PUSH EAX                                 ; |ShareMode
0045698A   PUSH ECX                                 ; |Access
0045698B   PUSH DWORD PTR SS:[EBP+8]                ; |FileName
0045698E   CALL DWORD PTR DS:[<&KERNEL32.CreateFile>; /CreateFileA
程序会先把参数反向压入堆栈,然后是一个CALL,我们清楚的看到,这个call的就是kernel32里的CreateFileA函数,继续跟踪:
7C801A28  MOV EDI,EDI
7C801A2A  PUSH EBP
7C801A2B  MOV EBP,ESP
7C801A2D  PUSH DWORD PTR SS:[EBP+8]
7C801A30  CALL 7C80E114
7C801A35  TEST EAX,EAX
7C801A37  JE SHORT 7C801A57
7C801A39  PUSH DWORD PTR SS:[EBP+20]        ;hTemplateFile
7C801A3C  PUSH DWORD PTR SS:[EBP+1C]         ; |Attributes
7C801A3F  PUSH DWORD PTR SS:[EBP+18]           ; |Mode
7C801A42  PUSH DWORD PTR SS:[EBP+14]        ; |pSecurity
7C801A45  PUSH DWORD PTR SS:[EBP+10]        ; |ShareMode
7C801A48  PUSH DWORD PTR SS:[EBP+C]        ; |Access
7C801A4B  PUSH DWORD PTR DS:[EAX+4]       ; |FileName
7C801A4E  CALL CreateFileW                 ; /CreateFileW
 
这段代码中有两个call,第一个CALL 7C80E114,跟进代码:
7C80E11C   MOV EAX,DWORD PTR FS:[18]
7C80E122   PUSH DWORD PTR SS:[EBP+8]
7C80E125   LEA ESI,DWORD PTR DS:[EAX+BF8]
7C80E12B   LEA EAX,DWORD PTR SS:[EBP-8]
7C80E12E   PUSH EAX
7C80E12F   CALL DWORD PTR DS:[<&ntdll.RtlInitAnsiString>]  
7C80E135   CMP DWORD PTR DS:[7C8856E0],0
7C80E13C   PUSH 0
7C80E13E   LEA EAX,DWORD PTR SS:[EBP-8]
7C80E141   PUSH EAX
7C80E142   PUSH ESI
7C80E143   JE 7C81CDA6
7C80E149   CALL DWORD PTR DS:[<&ntdll.RtlAnsiStringToUnicodeString>] 
7C80E14F   TEST EAX,EAX
7C80E151   JL 7C843C0D
7C80E157   MOV EAX,ESI
7C80E159   POP ESI
当然,我们已经猜到,这个调用,有两个功能,第一个就是初始化ANSI字符串,第二个就是把ANSI字符转换到UNICODE字符,我们返回到CreateFileA反汇编代码下,就知道CreateFileA函数其实只是负责转换字符串的,最终还是要调用CreateFileW字符,接下来,我们要到NATIVE API咯....
跟踪CreateFileW函数,发现这样一段代码:
7C8109B0  CALL DWORD PTR DS:[<&ntdll.NtCreateFile>]
到这里又一个新东西出现了,即ZwCreateFile和NtCreateFile,这两个函数由NTDLL.DLL导出,反汇编看一下ZwCreateFile函数的代码:
.text:7C92D0AE       mov     eax, 25h        ;
.text:7C92D0B3       mov     edx, 7FFE0300h
.text:7C92D0B8       call    dword ptr [edx]
.text:7C92D0BA       retn    2Ch
25h是ntoskrnl.exe中NtCreateFile的服务ID十进制是37,7FFE0300是参数起始地址
下面是NTDLL.DLL中NtCreateFile反汇编代码:
.text:7C92D0AE   mov     eax, 25h        ; NtCreateFile
.text:7C92D0B3   mov     edx, 7FFE0300h
.text:7C92D0B8   call    dword ptr [edx]
.text:7C92D0BA   retn    2Ch
不难看出,Ntdll中Zw与Nt函数的实现是完全一样的,至于为什么要出现两套名字不同,实现方式完全一样的函数,这两种函数,姑且可以这样表示
Typedef Zw Nt   O(∩_∩)O
上面讨论的就是所谓的native API,这是用户模式下最底层的函数了,但是为什么会有这两种函数?接下来就进入windows内核大世界探索这个问题.
Ntdll.dll 通过软件中断 int 2Eh 进入 ntoskrnl.exe,就是通过中断门切换CPU特权级,CPU特权级共有4个级别,分别是ring0,ring1,ring2,ring3,windows只使用其中两个ring0和ring3特权,ring0拥有最高权限,执行任意代码,windows的核心就在这个特权级运行,ring3是最低权限,int 2eh 使cpu从ring3级切换到ring0级,接着上面的代码,从用户模式进入内核模式,只传递了两个参数,一个是系统服务ID一个是参数地址,服务ID有什么用呢?其实在 Windows NT 中默认存在两个系统服务调度表,它们对应了两类不同的系统服务。这两个系统服务调度表
分别是:KeServiceDescriptorTable WDBG看一下:
kd> dd KeServiceDescriptorTable
80554020  80502bbc 00000000 0000011c 80503030
80554030  00000000 00000000 00000000 00000000
80554040  00000000 00000000 00000000 00000000
80554050  00000000 00000000 00000000 00000000
80554060  00002710 bf80c391 00000000 00000000
80554070  f8974a80 81f17ba8 81e4a5f0 806e2f40
80554080  00000000 00000000 00000000 00000000
80554090  c8c5ad40 01cb6858 00000000 00000000
KeServiceDescriptorTable中就只有第一项有数据,其他都是0。其中80502bbc就是KeServiceDescriptorTable.ntoskrnel.ServiceTableBase,服务函数个数为0x11c个,十进制表示为284。再看看80502bbc地址里是什么:
kd> dd 80502bbc
80502bbc  8059a9ba 805e7e36 805eb694 805e7e68
80502bcc  805eb6ce 805e7e9e 805eb712 805eb756
80502bdc  8060cea8 8060dbec 805e3234 805e2e8c
80502bec  805cbe66 805cbe16 8060d4ce 805ac62e
80502bfc  8060cae6 8059ee30 805a6a70 805cd944
80502c0c  80500838 8060e12a 8056cd48 8053603e
80502c1c  8060617e 805b2cba 805ebbce 8061af14
80502c2c  805f00e2 8059b0a8 8061b168 8059a95a
上面这些就是系统服务函数的地址了,当我们在ring3调用CreateFile时,进入sysenter的ID是0x25H(XP SP3),然后系统查KeServiceDescriptorTable,大概公式是:KeServiceDescriptorTable.ntoskrnel.ServiceTableBase(80502bbc) + 0x25H * 4,看一下:
kd> dd 80502bbc+25H*4
80502c50  8056f2ee 8056eccc 805cc908 805cc640
80502c60  8061b344 8056f3fc 8060e868 8056f328
80502c70  805a1e18 8059b476 805c84a0 805c83ea
80502c80  8060ec88 805a175c 8060c204 805ba614
80502c90  805c8288 8060e138 805f048a 8059b49a
80502ca0  8063adbc 8063af0c 8060db3c 8060d35e
80502cb0  8060e12a 8056ce8e 8061b7e0 805ebcda
80502cc0  8061b9b0 8056f4b4 8060a178 805b48ce
其中80502c50指向8056f2ee,这个就是NtCreateFile的真正地址,跟进看:
kd> u 8056f2ee L7
nt!NtCreateFile:
8056f2ee 8bff            mov     edi,edi
8056f2f0 55              push    ebp
8056f2f1 8bec            mov     ebp,esp
8056f2f3 33c0            xor     eax,eax
8056f2f5 50              push    eax
8056f2f6 50              push    eax
8056f2f7 50              push    eax
此结构定义如下:
typedef struct ServiceDescriptorTable
{
   PVOID ServiceTableBase;  //服务基址
   PVOID ServiceCounterTable(0);//服务调用次数
   unsigned int NumberOfServices;//服务个数
   PVOID ParamTableBase;//统服务参数字节数表的基地址
 }SYSTEM_DESCRIPTOR_TABLE,*PSYSTEM_DESCRIPTOR_TABLE;这个表由ntoskrnl.exe导出,另外系统中存在另一个服务描述表KeServiceDescriptorTableShadow,其指在GUI线程中使用,user32.dll和gdi32.dll两个库依赖此结构,定义如下:
typedef struct KeServiceDescriptorTableShadow
{
   SYSTEM_SERVICE_TABLE ntoskrnel; //ntoskrnl.exe的服务函数
   SYSTEM_SERVICE_TABLE win32k; //win32k.sys的服务函数
   SYSTEM_SERVICE_TABLE NotUsed1;
   SYSTEM_SERVICE_TABLE NotUsed2;
}SYSTEM_DESCRIPTOR_TABLE,*PSYSTEM_DESCRIPTOR_TABLE;这个表未导出,不过确实存在于Win32.sys中,由于涉及GUI线程,不在本文谈论范围,略过.....
原理知道了,接下来讲解刚才留下的问题,为什么会有这两种函数?在内核中叶存在一套与NATIVE API类似的函数,Zw*和Nt*,下面做一下对比:
kd> u NT! ZWCREATEFILE 
nt!ZwCreateFile:
804ff08c b825000000      mov     eax,25h
804ff091 8d542404        lea     edx,[esp+4]
804ff095 9c              pushfd
804ff096 6a08            push    8
又一次出现25h,这和ntdll中的ZwCreateFile还有NtCreateFile又一样了,重温一下:
.text:7C92D0AE   mov     eax, 25h        ; NtCreateFile /  ZwCreateFile
.text:7C92D0B3   mov     edx, 7FFE0300h
.text:7C92D0B8   call    dword ptr [edx]
.text:7C92D0BA   retn    2Ch
Ntoskrnl中的Nt函数:
kd> u nt! ntcreatefile L14
nt!NtCreateFile:
8056f2ee 8bff            mov     edi,edi
8056f2f0 55              push    ebp
8056f2f1 8bec            mov     ebp,esp
8056f2f3 33c0            xor     eax,eax
8056f2f5 50              push    eax
8056f2f6 50              push    eax
8056f2f7 50              push    eax
8056f2f8 ff7530          push    dword ptr [ebp+30h]
8056f2fb ff752c          push    dword ptr [ebp+2Ch]
8056f2fe ff7528          push    dword ptr [ebp+28h]
8056f301 ff7524          push    dword ptr [ebp+24h]
8056f304 ff7520          push    dword ptr [ebp+20h]
8056f307 ff751c          push    dword ptr [ebp+1Ch]
8056f30a ff7518          push    dword ptr [ebp+18h]
8056f30d ff7514          push    dword ptr [ebp+14h]
8056f310 ff7510          push    dword ptr [ebp+10h]
8056f313 ff750c          push    dword ptr [ebp+0Ch]
8056f316 ff7508          push    dword ptr [ebp+8]
8056f319 e860d8ffff      call    nt!IoCreateFile (8056cb7e)
8056f31e 5d              pop     ebp
通过对比,我们就可以刚才那个问题了:Zw*函数集合将从用户模式转入内核模式,而Nt*符号直接指向的代码会在模式切换后被执行.这个理解了,继续工作,
上面的代码有一句8056f319 e860d8ffff      call    nt!IoCreateFile (8056cb7e)
,看来要继续跟进:
kd> u nt!IoCreateFile L40
nt!IoCreateFile:
8056cb7e 8bff            mov     edi,edi
8056cb80 55              push    ebp
8056cb81 8bec            mov     ebp,esp
8056cb83 83ec0c          sub     esp,0Ch
8056cb86 53              push    ebx
8056cb87 56              push    esi
8056cb88 33f6            xor     esi,esi
8056cb8a 8975fc          mov     dword ptr [ebp-4],esi
8056cb8d 8b1db80b5580    mov     ebx,dword ptr [nt!KeI386MachineType+0x3634 (80550bb8)]
8056cb93 f6c301          test    bl,1
8056cb96 7443            je      nt!IoCreateFile+0x5d (8056cbdb)
8056cb98 8b45fc          mov     eax,dword ptr [ebp-4]
8056cb9b ff45fc          inc     dword ptr [ebp-4]
8056cb9e 85c0            test    eax,eax
8056cba0 7439            je      nt!IoCreateFile+0x5d (8056cbdb)
8056cba2 8b45fc          mov     eax,dword ptr [ebp-4]
8056cba5 6aff            push    0FFFFFFFFh
8056cba7 99              cdq
8056cba8 68f0d8ffff      push    0FFFFD8F0h
8056cbad 52              push    edx
8056cbae 50              push    eax
8056cbaf e8ac9efcff      call    nt!allmul (80536a60)
8056cbb4 817dfce8030000  cmp     dword ptr [ebp-4],3E8h
8056cbbb 8945f4          mov     dword ptr [ebp-0Ch],eax
8056cbbe 8955f8          mov     dword ptr [ebp-8],edx
8056cbc1 7e07            jle     nt!IoCreateFile+0x4c (8056cbca)
8056cbc3 c745fce8030000  mov     dword ptr [ebp-4],3E8h
8056cbca 8d45f4          lea     eax,[ebp-0Ch]
8056cbcd 50              push    eax
8056cbce 56              push    esi
8056cbcf 56              push    esi
8056cbd0 e811daf8ff      call    nt!KeDelayExecutionThread (804fa5e6)
8056cbd5 8b1db80b5580    mov     ebx,dword ptr [nt!KeI386MachineType+0x3634 (80550bb8)]
8056cbdb 56              push    esi
8056cbdc 56              push    esi
8056cbdd ff753c          push    dword ptr [ebp+3Ch]
8056cbe0 ff7538          push    dword ptr [ebp+38h]
8056cbe3 ff7534          push    dword ptr [ebp+34h]
8056cbe6 ff7530          push    dword ptr [ebp+30h]
8056cbe9 ff752c          push    dword ptr [ebp+2Ch]
8056cbec ff7528          push    dword ptr [ebp+28h]
8056cbef ff7524          push    dword ptr [ebp+24h]
8056cbf2 ff7520          push    dword ptr [ebp+20h]
8056cbf5 ff751c          push    dword ptr [ebp+1Ch]
8056cbf8 ff7518          push    dword ptr [ebp+18h]
8056cbfb ff7514          push    dword ptr [ebp+14h]
8056cbfe ff7510          push    dword ptr [ebp+10h]
8056cc01 ff750c          push    dword ptr [ebp+0Ch]
8056cc04 ff7508          push    dword ptr [ebp+8]
8056cc07 e882f2ffff      call    nt!IoCreateDevice+0x346 (8056be8e)
8056cc0c 3bc6            cmp     eax,esi
8056cc0e 7d15            jge     nt!IoCreateFile+0xa7 (8056cc25)
8056cc10 f6c301          test    bl,1
8056cc13 0f8574ffffff    jne     nt!IoCreateFile+0xf (8056cb8d)
8056cc19 3b1db80b5580    cmp     ebx,dword ptr [nt!KeI386MachineType+0x3634 (80550bb8)]
8056cc1f 0f8568ffffff    jne     nt!IoCreateFile+0xf (8056cb8d)
8056cc25 5e              pop     esi
8056cc26 5b              pop     ebx
8056cc27 c9              leave
8056cc28 c23800          ret     38h
这个函数由I/O管理器通过IoCreateFile创建IRP(IRP_CREATE_OPERATION),I/O管理器把此信号传递给文件系统驱动,文件系统驱动通过与硬件抽象层HAL.DLL与磁盘交互,如果创建成功,会返回一个NTSTATUS_SUCCESS,如果失败会根据失败原因返回相应的错误代码,设置IRP一个状态子域,PIRP->Iostatus.Status = status,IoCreateFile返回的是一个文件对象,然后此对象交给对象管理器负责转换,调用
VOID ObReferenceObject(
    IN PVOID  Object
  );内核把这个句柄返回给系统,如果失败,应用程序可通过GetLastError获得失败原因.
只能写这么点了,好多方面并没有提到,也很重要的,主要本人知识未到位,后面这些纯属个人理解..

ntdll.dll导出函数统计 主要记录ntdll.dll导出的所有函数。可以查看所有导出的函数 立即下载

相关推荐

辩论赛计时器微信小程序

一个非常完整的微信小程序,包括音效、动画、计时器功能,是学习的好例子。

printf函数打印(一)—— 过程解析篇

printf函数是如何打印数据的?首先需要知道打印的基本流程,再通过例子了解,printf本该打印的内容被写到了哪个文件里

challenglistic的博客 3147

ntdll中一些未公开函数

ntdll中一些未公开函数,英文chm文件

13.1 打印基础

摘录于《Windows程序(第5版,珍藏版).CHarles.Petzold 著》P471         在 Windows 中使用打印机时,你实际上启动了一系列模块之间复杂的交互过程,包括 GDI32 库模块、打印机设备驱动程序库模块(带 .DRV 后缀的文件)、Windows 后台打印机处理程序(print spooler)和其他有关模块。在开始为打印机编程之前,让我们先来看一下这

wilim 1303

ArcGIS拓扑面错误批量修改

在工作学习中经常会遇到拓扑修改的问题,当数据量巨大的时候会产生拓扑问题 当拓扑错误数量巨大时,人工逐一修改是不现实的,基于此利用gis自带工具箱实现拓扑面类错误的批量修改。 一、.常见拓扑错误的类型: 1面重叠 2空隙(绿色部分) 二、拓扑检查 1新建数据库-----新建数据集—导入数据. 2新建拓扑 3修改拓扑容差及名称 添加拓扑修改规则 完成拓扑检查-查看拓扑错误 三、拓扑批量...

qq_43173805的博客 3万+

模拟量传输4-20ma电流

大家可能会非常熟悉RS232,RS485,CAN等工业上常用的总线,他们都是传输数字信号的方式。那么,我们用什么方式来传输模拟信号呢?工业上普遍需要测量各类非电物理量,例如温度、压力、速度、角度等,这些都需要转换成模拟量电信号才能传输到几百米外的控制室或显示设备上。工业上最广泛采用的是用4~20mA电流来传输模拟量。 采用电流信号的原因是不容易受干扰,因为工业现场的噪声电压的幅度可能达到数V,但是噪声的功率很弱,所以噪声电流通常小于nA级别,因此给4-20mA传输带来的误差非常小;电流源内阻趋于无穷.

tangdongming的博客 1万+

用W32asm反汇编Ntdll.dll文件的后的代码

之所以要反汇编这个文件是想查看其调用的函数信息,但是反汇编后还是不明白一下内容里有什么有用的信息,求解释。 Object01: .text RVA: 00001000 Offset: 00000400 Size: 000D5200 Flags: 60000020 Object02: RT RVA: 000D7000 Offset: 000D5600 Size: 00000200 F...

kanwoerzi 198

疾病负担研究(GBD)——如何使用joinpoint软件计算AAPC

疾病负担研究(GBD)——如何使用joinpoint软件计算AAPC

weixin_44240228的博客 1万+

MS05-043漏洞利用分析以及ntdll!RtlFreeHeap中关于lookaside链表的操作

环境:windows2000 sp4 Rollup1使用工具:IDA v4.7softice这个漏洞出问题的代码是spoolsv.exe静态加载spoolss.dll,由spoolss.dll动态加载win32spl.dll中的函数:AddPrinterW具体可以参见:http://blog.0x557.org/Sandro/archives/0day_develop/index.html(同时表

1172

BeckHoff <--> ABB 机器手 Profinet 通讯

本文介绍了BeckHoff PLC与ABB机器人通过PROFINET通信的实现方案。主要内容包括:1)通信接口的详细变量定义,涵盖输入/输出信号、设备状态监控、夹爪控制等关键功能位;2)全局数据结构和变量配置说明;3)机器人任务控制程序的实现方法,包括参数校验、任务指令下发和状态监控机制;4)重点分析了任务调度功能块的代码逻辑,涉及慢速模式处理、多参数配置和执行状态判断。该方案通过结构化变量定义和模块化程序设计,实现了PLC对机器人作业的精确控制,为工业自动化系统集成提供了可靠通信范例。

工控智联驿站 1032

基于python+flask框架的基于微信小程序的CR公司建设项目信息管理系统-前台(开题+程序+论文) 计算机毕设

特别是随着移动互联网技术的普及,企业对便捷、高效的信息管理系统的需求日益迫切。另一方面,该系统集成了仓管、物料、财务、人事、供应商等多个模块,实现了数据的集中管理和信息共享,有助于企业实现精细化管理,降低运营成本,提升决策效率。:深入调研CR公司的业务需求,明确系统应具备的功能模块,包括仓管员管理模块(物料信息、退回记录、申请信息、仓库信息管理)、财务员管理模块(资金信息管理、采购与租赁款项处理)、人事管理模块、供应商管理模块、项目管理模块(项目信息、设备采购、物料采购、设备租赁)、以及考勤打卡模块等。

zhihao503的博客 960

Microsoft Edge 浏览器远程代码执行漏洞POC及细节(CVE-2017-8641)

2017年8月8日,CVE官网公布了CVE-2017-8641,在其网上的描述为: 意思是说,黑客可以通过在网页中嵌入恶意构造的javascript代码,使得微软的浏览器(如Edege),在打开这个网页时,造成堆溢出。通过精心构造javascript代码,可以通过浏览器在用户电脑上执行任意代码。受影响的版本包括下列操作系统中的浏览器(IE(9,10,11)和Edge): 1. Window...

weixin_30433075的博客 626

Elasticsearch 8.17.1 JAVA工具类

整理了Elasticsearch8.17最新版的API工具类

weixin_39555954的博客 1123

在Ring0下HOOK Ntdll.dll的Nt*函数的方法

typedef struct _SECTION_IMAGE_INFORMATION { PVOID EntryPoint; ULONG StackZeroBits; ULONG StackReserved; ULONG StackCommit; ULONG ImageSubsystem; WORD SubsystemVersionLow; WORD SubsystemVe

坦然 3093

数据库常见面试题(附答案)

1.事务四大特性 原子性,要么执行,要么不执行 隔离性,所有操作全部执行完以前,其它会话不能看到过程 一致性,事务前后,数据总额一致 持久性,一旦事务提交,对数据的改变就是永久的 2.数据库隔离级别,每个级别会引发什么问题,mysql默认是哪个级别 脏读:事务B读取事务A还没有提交的数据 不可重复读:两次事务读的数据不一致 幻读:事务A修改了数据,事务B也修改了数据,这时在事务A看...

csdn问鼎 46万+

SAP ABAP 缓冲同步揭秘——从 DDLOG 表到 RSDBBUF3 的完整实践指南

DDLOG 看似一张不起眼的系统表,却承担着 SAP 多实例环境下的数据一致性重任。通过掌握其字段意义、解析方法及周边监控工具,你可以在性能与一致性之间找到最佳平衡;通过精细化的参数管理与主动刷新策略,更能在关键业务场景中确保“数据永远是最新的”。愿本文能成为你日常排障与架构决策的参考手册。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 311

自己调用NTDLL函数

一、概述 在DLL初始化的时候有时不能调用其它系统DLL的函数,以免导致问题,但有时候又必须要调用怎么办?一种办法就是自己直接调用NTDLL接口,这样肯定没有问题。 下面我写个自己调用Registry的封装类,用来代替原本系统注册表API。 二、申明NTDLL导出函数 在自己工程中需要调用NTDLL导出函数,可以通GetProcessAddr来获取函数地址再调用,也可以通过导入库的方式(这种需...

weixin_34066347的博客 744

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

call ntdll.RtlUnicodeStringToAnsiString

前言要模拟GetModuleFileNameA中Unicode串转Ansi串的实现, 用OD看到核心函数调用是ntdll.RtlUnicodeStringToAnsiString代码片段// hw.cpp : Defines the entry point for the console application. //#include "stdafx.h" #include <windows.h>

博客标题不能为空 1252

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

NASM 纯汇编打造简单中文操作系统(4 mouse.inc 鼠标驱动部分(设置鼠标中断,建立中断处理程序))

四、mouse.inc 鼠标驱动部分(设置鼠标中断,建立中断处理程序)[BITS 32][ORG 0x0];鼠标中断处理程序INT_MOUSE: PUSHAD PUSHF;刷新鼠标所在区域 ReadPort 0x60 MOV AH,0   CMP [DS:SYSVAR+0x10],BYTE 0 JZ c0 CMP [DS:SYSVAR+0x10],BYTE 1 JZ c1 CMP [DS:

kylixfire的专栏 2409

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

工厂设备接MES为什么慢:协议识别与点表配置自动化的技术拆解

工业现场设备接 MES 的周期主要消耗在协议识别与点表配置。本文拆解这条链路的四层结构,给出点表映射的数据模型、两种部署架构的对比,以及可直接落地的三项验收口径与校验代码。适合工控集成、MES 实施、设备联网方向的工程师。

emfuture的博客 368

list

的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。,因此反向迭代器的实现可以借助正向迭代器,即:反向迭代器内部可以包含一个正向迭代器,对正向迭代器的接口进行包装即可。是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。迭代到该位置,在这段位置上迭代需要线性的时间开销;最大的缺陷是不支持任意位置的随机访问,比如:要访问。还需要一些额外的空间,以保存每个节点的相关联信息。个元素,必须从已知的位置。

xie0510_的博客 265

向 excel、word、pdf 三种文档中占位符插入数据

【代码】向 excel、word、pdf 三种文档中占位符插入数据。

weixin_45934659的博客 43

C++ STL 反向迭代器:从源码框架到适配器实现

在 C++ STL 中,反向迭代器(reverse_iterator)是一个很典型的设计案例:它本身并不直接持有容器数据,而是通过封装一个正向迭代器,把「前进」变成「后退」,从而让同一个容器既能正序遍历,也能逆序遍历。本文从 SGI-STL 3.0 的源码框架出发,梳理反向迭代器的设计思路,再手写一个通用的迭代器适配器,并在vector和list中完成适配与测试。在 SGI-STL 3.0 中,反向迭代器的核心源码位于。反向迭代器是一个适配器,各个容器再基于它适配出自己的反向迭代器类型。下面截取list。

Godbro的博客 229

[C++]:7.STL:list

好久不见,firdawn小课堂又和大家见面啦。今天我们要学习的内容是list容器,list也是一种常用的数据结构。下面是本章的思维导图,那么让我们开始学习吧!自定义的list,由三个结构构成。分别是链表的最小组成单位,也就是链表节点。以及迭代器类和list类其实要特别说明的是, List的迭代器,它不是单纯的指针,因为我们如果对指针直接进行解引用操作的话,我们得到的是这个节点,而不是节点里面存储的值并且我们对这个指针加加,得到的也不是下一个节点的地址,而是所在节点的下一个单位的地址。

2301_80817679的博客 172
上一篇: 最近
下一篇: 总结下windbg的常用命令
开发随笔
博客等级 码龄19年 6粉丝 10原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值