逆向分析并重组源码的过程
文章作者:asm
信息来源:邪恶八进制信息安全团队
   又屈服在goldberg的淫威下了。麻痹,一提到此人我就性趣勃勃。或许是他给俺力量,刚和他聊完,就怀上了这篇文章,由此可见,goldberg的能力之强。废话少说了,文章开始临盆。
    .text:0001045A
    .text:0001045A ; Attributes: bp-based frame
    .text:0001045A
    .text:0001045A                public start
    .text:0001045A start          proc near
    .text:0001045A                push    ebp  ;很多时候,我们把push 一个数据作为一个
    ;函数的参数对待。但是push也可以保存临时值。
    .text:0001045B                mov    ebp, esp        ; 把esp保存到ebp中去,开始进入函数体
    .text:0001045D                push    offset s_PI    ; "驱动入口\r\n"
    .text:00010462                call    DbgPrint        ; 格式化输出
    .text:00010462
    .text:00010467                add    esp, 4          ; 堆栈由函数自己清除
    .text:0001046A                call    sub_10260      ; 调用一个子函数
    .text:0001046A
    .text:0001046F                call    sub_10309      ; 调用一个子函数
    .text:0001046F
    .text:00010474                call    sub_10397      ; 调用一个子函数
    .text:00010474
    .text:00010479                push    offset asc_1068C ; "执行完退出\r\n\r\n"
    .text:0001047E                call    DbgPrint        ; 函数执行完毕
    .text:0001047E
    .text:00010483                add    esp, 4          ; 这里和上面一样,C的规则,由函数自己清空堆栈。汇编和C都沿用stdcall,必须这样
    .text:00010486                mov    eax, 0C0000182h ; 这里是驱动程序的返回,即 mov eax,STATUS_DEVICE_CONFIGURATION_ERROR
    .text:0001048B                leave
    .text:0001048C                retn    8
    .text:0001048C
    .text:0001048C start          endp
这里,我们已经构造出整个程序的结构。即:格式化打印信息—–分别调用三个子函数——-程序返回。这样一来,就可以重组出这个代码的框架:
    .386
    .model flat, stdcall
    option casemap:none
    ;
    ;这里包含用到的头文件和库。具体是哪个,还得进一步分析这个程序到底有到哪些函数
    .data?
    .
    .data
    .
    .const
    .code
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    DriverEntry proc pDriverObject:PDRIVER_OBJECT, pusRegistryPath:PUNICODE_STRING
Invoke DbgPrint,CTXT(“驱动入口”)
    call    sub_10260 ;调用第一个子函数,姑且这么写
    call    sub_10309
    call    sub_10397
    Invoke DbgPrint,CTXT(“程序结束”)
    mov eax,STATUS_DEVICE_CONFIGURATION_ERROR
    ret
    DriverEntry endp
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    end DriverEntry
就像建筑一栋大楼,把主干已经弄好,现在轮到添枝加叶。先看第一个子函数sub_10260。这里直接call调用了,所以就不存在任何参数传递。
    .text:00010260 sub_10260      proc near         
    .text:00010260
    .text:00010260 Handle          = dword ptr -24h ; 参数定义。如果是正的,就是局部变量
    .text:00010260 IoStatusBlock  = _IO_STATUS_BLOCK ptr -20h ;参数。这里IDA也已经给出结构
    .text:00010260 ObjectAttributes= OBJECT_ATTRIBUTES ptr -18h
    .text:00010260
    .text:00010260                push    ebp
    .text:00010261                mov    ebp, esp
    .text:00010263                add    esp, 0FFFFFFDCh
    .text:00010266                push    ds:off_10538
    .text:0001026C                push    offset Format  ; "创建目录: %ws \r\n"
    .text:00010271                call    DbgPrint        ; %ws是Unicode,在内核中是使用Unicode
    .text:00010271
    .text:00010276                add    esp, 8
    .text:00010279                lea    ecx, [ebp+ObjectAttributes] ; 初始化OBJ_CASE_INSENSITIV
    .text:0001027C                mov    dword ptr [ecx], 18h
    .text:00010282                and    dword ptr [ecx+4], 0
    .text:00010286                mov    dword ptr [ecx+0Ch], 240h
    .text:0001028D                and    dword ptr [ecx+10h], 0
    .text:00010291                mov    dword ptr [ecx+8], offset asc_10534 ; " \""
    .text:00010298                and    dword ptr [ecx+14h], 0
    .text:0001029C                push    0              ; EaLength
    .text:0001029E                push    0              ; EaBuffer
    .text:000102A0                push    21h            ; CreateOptions
    .text:000102A2                push    3              ; CreateDisposition
    .text:000102A4                push    0              ; ShareAccess
    .text:000102A6                push    80h            ; FileAttributes
    .text:000102AB                push    0              ; AllocationSize
    .text:000102AD                lea    eax, [ebp+IoStatusBlock]
    .text:000102B0                push    eax            ; IoStatusBlock
    .text:000102B1                lea    eax, [ebp+ObjectAttributes]
    .text:000102B4                push    eax            ; ObjectAttributes
    .text:000102B5                push    100000h        ; DesiredAccess
    .text:000102BA                lea    eax, [ebp+Handle]
    .text:000102BD                push    eax            ; FileHandle
    .text:000102BE                call    ZwCreateFile    ; 打开。内核中创建目录,
                                                          ;创建文件都使用这个函数
    .text:000102BE
    .text:000102C3                or      eax, eax        ; 返回值是否成功
    .text:000102C5                jnz    short loc_102F9 ; 不成功就跳到这里,
                                                          ;恰恰它格式化的代码已经提示我们,
                                                          ;目录创建失败
    .text:000102C5
    .text:000102C7                cmp    [ebp+IoStatusBlock.Information], 2 ; 这里查看文件的属性。
                                                                              ;2代表FILE_CREATED
    .text:000102CB                jnz    short loc_102DC ; 跳到 loc_102DC
    .text:000102CB
    .text:000102CD                push    offset s_I      ; "目录创建\r\n"
    .text:000102D2                call    DbgPrint
    .text:000102D2
    .text:000102D7                add    esp, 4          ; 恢复堆栈
    .text:000102DA                jmp    short loc_102EF ; 目录创建之后,就要关闭句柄
    .text:000102DA
    .text:000102DC ; ---------------------------------------------------------------------------
    .text:000102DC
    .text:000102DC loc_102DC:                         
    .text:000102DC                cmp    [ebp+IoStatusBlock.Information], 1 ; 测试文件的FILE_OPENED                                                                          ;属性。很明显,是.if--                                                                            ;-.elseif--.endif的结构
    .text:000102E0                jnz    short loc_102EF
    .text:000102E0
    .text:000102E2                push    offset s_KJ    ; "目录共享\r\n"
    .text:000102E7                call    DbgPrint
    .text:000102E7
    .text:000102EC                add    esp, 4
    .text:000102EC
    .text:000102EF
    .text:000102EF loc_102EF:                           
    .text:000102EF                                       
    .text:000102EF                push    [ebp+Handle]    ; Handle
    .text:000102F2                call    ZwClose        ; 两个属性测试完毕,目录才真正创建成功~!
    .text:000102F2
    .text:000102F7                jmp    short locret_10307 ; 函数返回
    .text:000102F7
    .text:000102F9 ; ---------------------------------------------------------------------------
    .text:000102F9
    .text:000102F9 loc_102F9:                           
    .text:000102F9                push    eax
    .text:000102FA                push    offset s_IIAI08x ; "无法创建目录,错误代码 %08X\r\n"
    .text:000102FF                call    DbgPrint
    .text:000102FF
    .text:00010304                add    esp, 8
    .text:00010304
    .text:00010307
    .text:00010307 locret_10307:                         
    .text:00010307                leave                  ; 程序返回
    .text:00010308                retn
    .text:00010308
    .text:00010308 sub_10260      endp
    首先这个子函数初始化OBJ_CASE_INSENSITIV结构。这个结构是这样的:
ObjectAttributes  OBJECT_ATTRIBUTES<?>。接着打印要创建的目录名。代码:
.const
CCOUNTED_UNICODE_STRING "\\??\\c:\\fuck", g_usDirName, 4
.
.
invoke DbgPrint, $CTA0("\创建目录: %ws \n"), g_usDirName.Buffer
在创建目录后同时测试其属性,分别打印。下面是重组的代码:
    CreateDirectory proc
    local oa:OBJECT_ATTRIBUTES
    local iosb:IO_STATUS_BLOCK
    local hDirectory:HANDLE
    ;------------------------------------------------------------
    ;Unicode格式化输出目录名。在内核使用Unicode
    ;------------------------------------------------------------
    invoke DbgPrint, $CTA0("创建目录: %ws "), g_usDirName.Buffer
      ;------------------------------------------------------------
    ; 初始化OBJ_CASE_INSENSITIVE,oa作为参数传递给ZwCreateFile
    ;------------------------------------------------------------
    InitializeObjectAttributes addr oa, addr g_usDirName, \
          OBJ_CASE_INSENSITIVE + OBJ_KERNEL_HANDLE, NULL, NULL   
    invoke ZwCreateFile, addr hDirectory, SYNCHRONIZE, addr oa, addr iosb, 0, FILE_ATTRIBUTE_NORMAL, \
          0, FILE_OPEN_IF, FILE_DIRECTORY_FILE + FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0
    .if eax == STATUS_SUCCESS
      ;------------------------------------------------------------
      ;文件创建属性
      ;------------------------------------------------------------
      .if iosb.Information == FILE_CREATED
      invoke DbgPrint, $CTA0("目录创建")
      ;------------------------------------------------------------
      ;文件共享属性     
      ;------------------------------------------------------------
      .elseif iosb.Information == FILE_OPENED
      invoke DbgPrint, $CTA0("目录共享")
      .endif
      invoke ZwClose, hDirectory
    .else
      ;------------------------------------------------------------
      ;格式化输出,创建目录失败!
      ;------------------------------------------------------------
      invoke DbgPrint, $CTA0("无法创建目录,错误代码 %08X"), eax
    .endif
    ret
    CreateDirectory endp
现在来看第二个子函数sub_10309。
    .text:00010309 sub_10309      proc near             
    .text:00010309
    .text:00010309 Handle          = dword ptr -24h  ;函数句柄
    .text:00010309 IoStatusBlock  = _IO_STATUS_BLOCK ptr -20h ;IO_STATUS_BLOCK结构
    .text:00010309 ObjectAttributes= OBJECT_ATTRIBUTES ptr -18h ;OBJECT_ATTRIBUTES结构
    .text:00010309
    .text:00010309                push    ebp
    .text:0001030A                mov    ebp, esp
    .text:0001030C                add    esp, 0FFFFFFDCh
    .text:0001030F                push    ds:off_1050C
    .text:00010315                push    offset s_IWs_0  ; "创建文件 %ws \r\n"
    .text:0001031A                call    DbgPrint        ; 这段代码很熟悉吧 :)
    .text:0001031A
    .text:0001031F                add    esp, 8
    .text:00010322                lea    ecx, [ebp+ObjectAttributes] ; 这段是不是也很熟悉 :)
    .text:00010325                mov    dword ptr [ecx], 18h
    .text:0001032B                and    dword ptr [ecx+4], 0
    .text:0001032F                mov    dword ptr [ecx+0Ch], 240h
    .text:00010336                and    dword ptr [ecx+10h], 0
    .text:0001033A                mov    dword ptr [ecx+8], offset s_24 ; "24"
    .text:00010341                and    dword ptr [ecx+14h], 0
    .text:00010345                push    0              ; EaLength
    .text:00010347                push    0              ; EaBuffer
    .text:00010349                push    20h            ; CreateOptions
    .text:0001034B                push    2              ; CreateDisposition
    .text:0001034D                push    0              ; ShareAccess
    .text:0001034F                push    80h            ; FileAttributes
    .text:00010354                push    0              ; AllocationSize
    .text:00010356                lea    eax, [ebp+IoStatusBlock]
    .text:00010359                push    eax            ; IoStatusBlock
    .text:0001035A                lea    eax, [ebp+ObjectAttributes]
    .text:0001035D                push    eax            ; ObjectAttributes
    .text:0001035E                push    100000h        ; DesiredAccess
    .text:00010363                lea    eax, [ebp+Handle]
    .text:00010366                push    eax            ; FileHandle
    .text:00010367                call    ZwCreateFile    ; 刚多说了,创建目录和创建文件都使用这个
    .text:00010367
    .text:0001036C                or      eax, eax
    .text:0001036E                jnz    short loc_10387
    .text:0001036E
    .text:00010370                push    offset s_IJ    ; "文件创建成功\r\n"
    .text:00010375                call    DbgPrint        ; 他已经提示我们文件创建成功了
    .text:00010375
    .text:0001037A                add    esp, 4
    .text:0001037D                push    [ebp+Handle]    ; Handle
    .text:00010380                call    ZwClose        ; 关闭句柄
    .text:00010380
    .text:00010385                jmp    short locret_10395 ; 交还控制权
    .text:00010385
    .text:00010387 ; ---------------------------------------------------------------------------
    .text:00010387
    .text:00010387 loc_10387:                         
    .text:00010387                push    eax
    .text:00010388                push    offset s_IZAI08x ; "文件创建失败,错误代码: %08X\r\n"
    .text:0001038D                call    DbgPrint
    .text:0001038D
    .text:00010392                add    esp, 8          ; 清除堆栈
    .text:00010392
    .text:00010395
    .text:00010395 locret_10395:                       
    .text:00010395                leave                  ; 每一个程序的最后都要把控制权交给主程序
    .text:00010396                retn
    .text:00010396
    .text:00010396 sub_10309      endp
和创建目录的一样,创建文件也是初始化OBJECT_ATTRIBUTES,调用ZwCreateFile。下面是源码:
    CreateFile proc
    local oa:OBJECT_ATTRIBUTES
    local iosb:IO_STATUS_BLOCK
    local hFile:HANDLE
    ;-----------------------------------------------------------
    ;
    ;格式化输出创建的文件名。在内核中使用Unicode
    ;Buffer缓冲区保存着文件路径
    ;
    ;-----------------------------------------------------------
    invoke DbgPrint, $CTA0("创建文件 %ws "), g_usFileName.Buffer
    ;-----------------------------------------------------------
      ;初始化OBJ_CASE_INSENSITIVE结构
      ;-----------------------------------------------------------
    InitializeObjectAttributes addr oa, addr g_usFileName, \
          OBJ_CASE_INSENSITIVE + OBJ_KERNEL_HANDLE, NULL, NULL
    ;-----------------------------------------------------------   
      ;打开文件
      ;-----------------------------------------------------------
    invoke ZwCreateFile, addr hFile, SYNCHRONIZE, addr oa, addr iosb, 0, FILE_ATTRIBUTE_NORMAL, \
          0, FILE_CREATE, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0
    .if eax == STATUS_SUCCESS
      invoke DbgPrint, $CTA0("文件创建成功")
      invoke ZwClose, hFile
    .else
      invoke DbgPrint, $CTA0("文件创建失败,错误代码: %08X"), eax
    .endif
    ret
    CreateFile endp
最后一个子函数sub_10397
    .text:00010397 sub_10397      proc near       
    .text:00010397
    .text:00010397 Handle          = dword ptr -24h
    .text:00010397 IoStatusBlock  = _IO_STATUS_BLOCK ptr -20h
    .text:00010397 ObjectAttributes= OBJECT_ATTRIBUTES ptr -18h
    .text:00010397
    .text:00010397                push    ebp
    .text:00010398                mov    ebp, esp
    .text:0001039A                add    esp, 0FFFFFFDCh
    .text:0001039D                push    offset s_KI    ; "打开文件准备写入数据\r\n"
    .text:000103A2                call    DbgPrint
    .text:000103A2
    .text:000103A7                add    esp, 4
    .text:000103AA                lea    ecx, [ebp+ObjectAttributes]
    .text:000103AD                mov    dword ptr [ecx], 18h
    .text:000103B3                and    dword ptr [ecx+4], 0
    .text:000103B7                mov    dword ptr [ecx+0Ch], 240h
    .text:000103BE                and    dword ptr [ecx+10h], 0
    .text:000103C2                mov    dword ptr [ecx+8], offset s_24 ; "24"
    .text:000103C9                and    dword ptr [ecx+14h], 0
    .text:000103CD                push    0              ; EaLength
    .text:000103CF                push    0              ; EaBuffer
    .text:000103D1                push    20h            ; CreateOptions
    .text:000103D3                push    1              ; CreateDisposition
    .text:000103D5                push    1              ; ShareAccess
    .text:000103D7                push    0              ; FileAttributes
    .text:000103D9                push    0              ; AllocationSize
    .text:000103DB                lea    eax, [ebp+IoStatusBlock]
    .text:000103DE                push    eax            ; IoStatusBlock
    .text:000103DF                lea    eax, [ebp+ObjectAttributes]
    .text:000103E2                push    eax            ; ObjectAttributes
    .text:000103E3                push    100002h        ; DesiredAccess
    .text:000103E8                lea    eax, [ebp+Handle]
    .text:000103EB                push    eax            ; FileHandle
    .text:000103EC                call    ZwCreateFile    ; 打开我们刚创建的文件
    .text:000103EC
    .text:000103F1                or      eax, eax
    .text:000103F3                jnz    short loc_1044A ; 无法写入文件
    .text:000103F3
    .text:000103F5                push    offset s_KJ_0  ; "文件打开成功\r\n"
    .text:000103FA                call    DbgPrint
    .text:000103FA
    .text:000103FF                add    esp, 4
    .text:00010402                push    0              ; Key
    .text:00010404                push    0              ; ByteOffset
    .text:00010406                push    4Dh            ; Length
    .text:00010408                push    offset Buffer  ; "这里是文件的内容"
    .text:0001040D                lea    eax, [ebp+IoStatusBlock]
    .text:00010410                push    eax            ; IoStatusBlock
    .text:00010411                push    0              ; ApcContext
    .text:00010413                push    0              ; ApcRoutine
    .text:00010415                push    0              ; Event
    .text:00010417                push    [ebp+Handle]    ; FileHandle
    .text:0001041A                call    ZwWriteFile    ; 写入数据。
    .text:0001041A
    .text:0001041F                or      eax, eax
    .text:00010421                jnz    short loc_10432
    .text:00010421
    .text:00010423                push    offset s_IJ_0  ; "文件写入成功\r\n"
    .text:00010428                call    DbgPrint
    .text:00010428
    .text:0001042D                add    esp, 4
    .text:00010430                jmp    short loc_10440
    .text:00010430
    .text:00010432 ; ---------------------------------------------------------------------------
    .text:00010432
    .text:00010432 loc_10432:                           
    .text:00010432                push    eax
    .text:00010433                push    offset s_IIAI08x_0 ; "无法写入文件,错误代码: %08X\r\n"
    .text:00010438                call    DbgPrint
    .text:00010438
    .text:0001043D                add    esp, 8
    .text:0001043D
    .text:00010440
    .text:00010440 loc_10440:                           
    .text:00010440                push    [ebp+Handle]    ; Handle
    .text:00010443                call    ZwClose
    .text:00010443
    .text:00010448                jmp    short locret_10458
    .text:00010448
    .text:0001044A ; ---------------------------------------------------------------------------
    .text:0001044A
    .text:0001044A loc_1044A:                           
    .text:0001044A                push    eax
    .text:0001044B                push    offset s_IKAI08x ; "无法打开文件,错误代码: %08X\r\n"
    .text:00010450                call    DbgPrint
    .text:00010450
    .text:00010455                add    esp, 8
    .text:00010455
    .text:00010458
    .text:00010458 locret_10458:                          ;提交控制权
    .text:00010458                leave
    .text:00010459                retn
    .text:00010459
    .text:00010459 sub_10397      endp
到此,三个未知的子函数已经逐一逆向出源码。程序的流程我们已经很清楚—创建目录—-创建文件—-写入数据到文件。现在整理一下得出完整代码:
    ;-----------------------------------------------
    ;
    ;code by  asm
    ;QQ 448761813
    ;
    ;-----------------------------------------------
    .386
    .model flat, stdcall
    option casemap:none
    ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    include w2k\ntstatus.inc
    include w2k\ntifs.inc
    include w2k\ntoskrnl.inc
    includelib ntoskrnl.lib
    include Strings.mac
    ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    ;利用宏定义文件路径和目录,还可以这样做:
    ;g_usFileName dw '\','?','?','c',':','\','F','i','l','e','W','o','r','k','s','\','t','e','s','t','.','t','x','t',0
    ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    .const
    CCOUNTED_UNICODE_STRING "\\??\\c:\\fuck\\test.txt", g_usFileName, 4
    CCOUNTED_UNICODE_STRING "\\??\\c:\\fuck", g_usDirName, 4
    ;CTA0 "fuck the world", g_szData,4
    ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    .code
    ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    ;创建目录函数                                           
    ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    CreateDirectory proc
    local oa:OBJECT_ATTRIBUTES
    local iosb:IO_STATUS_BLOCK
    local hDirectory:HANDLE
    ;------------------------------------------------------------
    ;Unicode格式化输出目录名。在内核使用Unicode
    ;------------------------------------------------------------
    invoke DbgPrint, $CTA0("创建目录: %ws "), g_usDirName.Buffer
      ;------------------------------------------------------------
    ; 初始化OBJ_CASE_INSENSITIVE,oa作为参数传递给ZwCreateFile
    ;------------------------------------------------------------
    InitializeObjectAttributes addr oa, addr g_usDirName, \
          OBJ_CASE_INSENSITIVE + OBJ_KERNEL_HANDLE, NULL, NULL   
    invoke ZwCreateFile, addr hDirectory, SYNCHRONIZE, addr oa, addr iosb, 0, FILE_ATTRIBUTE_NORMAL, \
          0, FILE_OPEN_IF, FILE_DIRECTORY_FILE + FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0
    .if eax == STATUS_SUCCESS
      ;------------------------------------------------------------
      ;文件创建属性
      ;------------------------------------------------------------
      .if iosb.Information == FILE_CREATED
      invoke DbgPrint, $CTA0("目录创建")
      ;------------------------------------------------------------
      ;文件共享属性     
      ;------------------------------------------------------------
      .elseif iosb.Information == FILE_OPENED
      invoke DbgPrint, $CTA0("目录共享")
      .endif
      invoke ZwClose, hDirectory
    .else
      ;------------------------------------------------------------
      ;格式化输出,创建目录失败!
      ;------------------------------------------------------------
      invoke DbgPrint, $CTA0("无法创建目录,错误代码 %08X"), eax
    .endif
    ret
    CreateDirectory endp
    ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    ;
    ;打开创建一个文件
    ;
    ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    CreateFile proc
    local oa:OBJECT_ATTRIBUTES
    local iosb:IO_STATUS_BLOCK
    local hFile:HANDLE
    ;-----------------------------------------------------------
    ;
    ;格式化输出创建的文件名。在内核中使用Unicode
    ;Buffer缓冲区保存着文件路径
    ;
    ;-----------------------------------------------------------
    invoke DbgPrint, $CTA0("创建文件 %ws "), g_usFileName.Buffer
    ;-----------------------------------------------------------
      ;初始化OBJ_CASE_INSENSITIVE结构
      ;-----------------------------------------------------------
    InitializeObjectAttributes addr oa, addr g_usFileName, \
          OBJ_CASE_INSENSITIVE + OBJ_KERNEL_HANDLE, NULL, NULL
    ;-----------------------------------------------------------   
      ;打开文件
      ;-----------------------------------------------------------
    invoke ZwCreateFile, addr hFile, SYNCHRONIZE, addr oa, addr iosb, 0, FILE_ATTRIBUTE_NORMAL, \
          0, FILE_CREATE, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0
    .if eax == STATUS_SUCCESS
      invoke DbgPrint, $CTA0("文件创建成功")
      invoke ZwClose, hFile
    .else
      invoke DbgPrint, $CTA0("文件创建失败,错误代码: %08X"), eax
    .endif
    ret
    CreateFile endp
    ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    ;
    ;开始把内容写入这个文件当中     
    ;
    ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    WriteFile proc
    local oa:OBJECT_ATTRIBUTES
    local iosb:IO_STATUS_BLOCK
    local hFile:HANDLE
      ;相当于C中的printf
    invoke DbgPrint, $CTA0("打开文件准备写入数据")
    InitializeObjectAttributes addr oa, addr g_usFileName, \
          OBJ_CASE_INSENSITIVE + OBJ_KERNEL_HANDLE, NULL, NULL
      ;-----------------------------------------------------------
      ;
      ; ZwCreateFile 用来打开文件,所以属性必须指定.
      ; 如果要对文件进行写操作,可以指定FILE_WRITE_DATA权限,这个和ring3一样
      ;
      ;-----------------------------------------------------------
    invoke ZwCreateFile, addr hFile, FILE_WRITE_DATA + SYNCHRONIZE, addr oa, addr iosb, \
          0, 0, FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0
    .if eax == STATUS_SUCCESS
      invoke DbgPrint, $CTA0("文件打开成功")
      ;-----------------------------------------------------------
      ;
          ;这里是文件内容,使用了CTA0 宏,也可以在.const段来定义
          ;CTA0 "Data can be written to an open file", g_szData,4
          ;使用何种定义,都是个人偏好。下面代码就没什么好注释的了
          ;
          ;-----------------------------------------------------------
          CTA0 "看KmdKit爽爽中,其内附一代码,其内容过于复杂,删几段修改测试之,成功,乃大喜,记之.",g_szData,4
      invoke ZwWriteFile, hFile, 0, NULL, NULL, addr iosb, \
          addr g_szData, sizeof g_szData - 1, NULL, NULL
      .if eax == STATUS_SUCCESS
      invoke DbgPrint, $CTA0("文件写入成功")
      .else
      invoke DbgPrint, $CTA0("无法写入文件,错误代码: %08X"), eax
      .endif
      invoke ZwClose, hFile
    .else
      invoke DbgPrint, $CTA0("无法打开文件,错误代码: %08X"), eax
    .endif
ret
    WriteFile endp                                         
    ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    ;
    ;驱动程序入口处
    ;
    ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
DriverEntry proc pDriverObject:PDRIVER_OBJECT, pusRegistryPath:PUNICODE_STRING
    invoke DbgPrint, $CTA0("驱动入口")
    ;---------------------------------------------------------------------
    ;调用函数创建一个目录.刚测试了一下,要创建一个文件,必须先创建其目录.
    ;这个ZwCreateFile不像ring3的一样,必须要创建文件的目录后,才能创建文件.
    ;---------------------------------------------------------------------
    invoke CreateDirectory
    invoke CreateFile      ;创建一个文件
    invoke WriteFile      ;把内容写到此文件中
    invoke DbgPrint, $CTA0("执行完退出")
    mov eax, STATUS_DEVICE_CONFIGURATION_ERROR ;获取失败消息返回
    ret
    DriverEntry endp
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    end DriverEntry
很简单的一个驱动程序。关于文件操作的。俺喜欢用IDA对程序进行白箱测试,有牛人说,学汇编最好的方法就是反汇编别人的程序。这句话俺深有体会。逆向技术在商业领域用途更广,并且逆向技术已经合法话,玩这个的更有发挥的空间。俺曾经听过一句铞言:给我一个可执行文件,我可以还你一份源码。可见威力。可惜俺的逆向功底不深,对驱动的逆向难免存在遗漏,请大大们指出,俺一定会改正。
当然,要对驱动的结构有很深的了解才能够分析。但是有些程序是exe的,但是却使用ntdll.dll里的函数,比如系统进程 lsass.exe。这里我简陋分析一下:
    .text:010014EC                push    esi            ; 保存寄存器值
    .text:010014ED                push    esi           
    .text:010014EE                push    1              ;千万别把1当作一个参数。
    .text:010014F0                call    loc_10013EF    ; 调用子函数
    ---------------------------------------------------------------------------
    ;看到这里就应该明白,这个子函数并没有任何参数传递。所以我也不明白 push 1 是什么意思
    loc_10013EF:
    .text:010013EF loc_10013EF:                       
    .text:010013EF                mov    edi, edi
    .text:010013F1                push    ebp
    .text:010013F2                mov    ebp, esp
    .text:010013F4                push    ecx
    .text:010013F5                push    esi            ; 上面这些操作都是保存寄存器的值,而非参数。即pushad
    .text:010013F6                push    1              ; SEM_NOGPFAULTERRORBOX
    .text:010013F8                call    ds:SetErrorMode ; 设置错误代码,如果程序出现异常,不提供任何提示
    .text:010013FE                push    offset loc_10011DD
    .text:01001403                call    ds:SetUnhandledExceptionFilter ; 程序错误则取其错误地址.这是一个回调函数
    .text:01001409                push    4
    .text:0100140B                lea    eax, [ebp-4]
    .text:0100140E                push    eax
    .text:0100140F                push    5
    .text:01001411                push    0FFFFFFFFh
    .text:01001413                mov    dword ptr [ebp-4], 9
    .text:0100141A                call    ds:NtSetInformationProcess ; 把与调度优先级有关的信息设置到目标进程对象中去。具体是什么,我也不清楚
    .text:01001420                mov    esi, eax        ; 保存函数返回值到esi
    .text:01001422                test    esi, esi        ; 为0否?
    .text:01001424                jl      short loc_1001486 ; 这里的esi是NtSetInformationProcess函数的返回值。通过堆栈直接传给这个子函数
------------------------------------------------------------------------------------
loc_1001486:
    .text:01001486 loc_1001486:                           
    .text:01001486                                       
    .text:01001486                                       
    .text:01001486                                     
    .text:01001486                                       
    .text:01001486                                       
    .text:01001486                push    esi            ; 这里的esi是NtSetInformationProcess函数的返回值。通过堆栈直接传给这个子函数
    .text:01001487                call    sub_10011EE
    .text:01001487
    .text:0100148C                push    esi
    .text:0100148D                call    ds:ExitThread
----------------------------------------------------------------------------------
sub_10011EE:
    .text:010011EE sub_10011EE    proc near           
    .text:010011EE
    .text:010011EE var_48          = dword ptr -48h
    .text:010011EE var_44          = dword ptr -44h
    .text:010011EE var_40          = dword ptr -40h
    .text:010011EE var_38          = dword ptr -38h
    .text:010011EE var_34          = dword ptr -34h
    .text:010011EE var_30          = dword ptr -30h
    .text:010011EE var_2C          = dword ptr -2Ch
    .text:010011EE var_28          = dword ptr -28h
    .text:010011EE var_24          = dword ptr -24h
    .text:010011EE var_20          = dword ptr -20h
    .text:010011EE hObject        = dword ptr -1Ch
    .text:010011EE pSid            = dword ptr -18h
    .text:010011EE var_14          = dword ptr -14h
    .text:010011EE var_10          = dword ptr -10h
    .text:010011EE pIdentifierAuthority= _SID_IDENTIFIER_AUTHORITY ptr -0Ch
    .text:010011EE var_4          = dword ptr -4
    .text:010011EE arg_0          = dword ptr  8 ;传递过来的NtSetInformationProcess函数句柄
    .text:010011EE
    .text:010011EE                mov    edi, edi
    .text:010011F0                push    ebp
    .text:010011F1                mov    ebp, esp
    .text:010011F3                sub    esp, 48h
    .text:010011F6                mov    eax, dword_1003004
    .text:010011FB                push    ebx
    .text:010011FC                push    esi
    .text:010011FD                mov    esi, [ebp+arg_0]
    .text:01001200                xor    ebx, ebx
    .text:01001202                cmp    esi, ebx
    .text:01001204                mov    [ebp+var_4], eax
    .text:01001207                push    edi
    .text:01001208                mov    [ebp+var_10], ebx
    .text:0100120B                jl      loc_1001298
    .text:0100120B
    .text:01001211                push    offset s_Sam_service_s ; "\\SAM_SERVICE_STARTED"
    .text:01001216                lea    eax, [ebp+var_40] ; 由此可见,var_40 是一个局部缓冲区变量
    .text:01001219                push    eax
    .text:0100121A                call    ds:RtlInitUnicodeString
    .text:01001220                push    ebx
    .text:01001221                lea    eax, [ebp+var_40]
    .text:01001224                mov    [ebp+var_2C], eax
    .text:01001227                push    ebx
    .text:01001228                lea    eax, [ebp+var_34]
    .text:0100122B                push    eax
    .text:0100122C                mov    esi, 100002h
    .text:01001231                push    esi
    .text:01001232                lea    eax, [ebp+var_10]
    .text:01001235                push    eax
    .text:01001236                mov    [ebp+var_34], 18h
    .text:0100123D                mov    [ebp+var_30], ebx
    .text:01001240                mov    [ebp+var_28], ebx
    .text:01001243                mov    [ebp+var_24], ebx
    .text:01001246                mov    [ebp+var_20], ebx
    .text:01001249                call    ds:NtCreateEvent ; 创建互拆对象,内核中代表着事件对象的数据结构是KEVENT
    .text:0100124F                cmp    eax, ebx        ; eax >= ebx ?
    .text:01001251                jge    short loc_1001278 ; 如果是,就跳
    .text:01001251
    .text:01001253                cmp    eax, 40000000h  ; eax == 40000000h ?
    .text:01001258                jz      short loc_1001261
    .text:01001258
    .text:0100125A                cmp    eax, 0C0000035h ; eax != 0C0000035h ?
    .text:0100125F                jnz    short loc_1001270
    .text:0100125F
    .text:01001261
    .text:01001261 loc_1001261:                         
    .text:01001261                lea    eax, [ebp+var_34]
    .text:01001264                push    eax
    .text:01001265                push    esi
    .text:01001266                lea    eax, [ebp+var_10]
    .text:01001269                push    eax
    .text:0100126A                call    ds:NtOpenEvent  ; 打开一个内核对象
    .text:0100126A
    .text:01001270
    .text:01001270 loc_1001270:                         
    .text:01001270                cmp    eax, ebx
    .text:01001272                jl      loc_10013DB
    .text:01001272
    .text:01001278
    .text:01001278 loc_1001278:                         
    .text:01001278                push    ebx
    .text:01001279                push    [ebp+var_10]
    .text:0100127C                call    ds:NtSetEvent  ; 设置内核对象
    .text:01001282                test    eax, eax
    .text:01001284                jge    loc_10013DB
    .text:01001284
    .text:0100128A                push    [ebp+var_10]
    .text:0100128D                call    ds:NtClose      ; 关闭
    .text:01001293                jmp    loc_10013DB
    .text:01001293
    .text:01001298 ; ---------------------------------------------------------------------------
    .text:01001298
    .text:01001298 loc_1001298:                           
    .text:01001298                push    2              ; ImpersonationLevel
    .text:0100129A                call    ds:ImpersonateSelf
    .text:010012A0                xor    edi, edi
    .text:010012A2                inc    edi
    .text:010012A3                test    eax, eax
    .text:010012A5                jz      loc_100133F
    .text:010012A5
    .text:010012AB                lea    eax, [ebp+hObject]
    .text:010012AE                push    eax            ; TokenHandle
    .text:010012AF                push    edi            ; OpenAsSelf
    .text:010012B0                push    8              ; DesiredAccess
    .text:010012B2                call    ds:GetCurrentThread ; 获取自身进程PID
    .text:010012B8                push    eax            ; ThreadHandle
    .text:010012B9                call    ds:OpenThreadToken ; Open the access token associated with a thread
    .text:010012BF                test    eax, eax
    .text:010012C1                jz      short loc_1001339
    .text:010012C1
    .text:010012C3                lea    eax, [ebp+pSid]
    .text:010012C6                push    eax            ; pSid
    .text:010012C7                push    ebx            ; nSubAuthority7
    .text:010012C8                push    ebx            ; nSubAuthority6
    .text:010012C9                push    ebx            ; nSubAuthority5
    .text:010012CA                push    ebx            ; nSubAuthority4
    .text:010012CB                push    ebx            ; nSubAuthority3
    .text:010012CC                push    ebx            ; nSubAuthority2
    .text:010012CD                push    ebx            ; nSubAuthority1
    .text:010012CE                push    12h            ; nSubAuthority0
    .text:010012D0                push    edi            ; nSubAuthorityCount
    .text:010012D1                lea    eax, [ebp+pIdentifierAuthority]
    .text:010012D4                push    eax            ; pIdentifierAuthority
    .text:010012D5                mov    [ebp+var_14], edi
    .text:010012D8                mov    [ebp+pSid], ebx
    .text:010012DB                mov    [ebp+pIdentifierAuthority.Value], bl
    .text:010012DE                mov    [ebp+pIdentifierAuthority.Value+1], bl
    .text:010012E1                mov    [ebp+pIdentifierAuthority.Value+2], bl
    .text:010012E4                mov    [ebp+pIdentifierAuthority.Value+3], bl
    .text:010012E7                mov    [ebp+pIdentifierAuthority.Value+4], bl
    .text:010012EA                mov    [ebp+pIdentifierAuthority.Value+5], 5
    .text:010012EE                call    ds:AllocateAndInitializeSid ; Allocate and initializes a security
    .text:010012EE                                        ; identifier with up to eight subauthorities
    .text:010012F4                test    eax, eax
    .text:010012F6                jz      short loc_100131F
    .text:010012F6
    .text:010012F8                lea    eax, [ebp+var_38]
    .text:010012FB                push    eax
    .text:010012FC                push    [ebp+pSid]
    .text:010012FF                push    [ebp+hObject]
    .text:01001302                call    CheckTokenMembership
    .text:01001302
    .text:01001307                test    eax, eax
    .text:01001309                jz      short loc_1001311
    .text:01001309
    .text:0100130B                mov    eax, [ebp+var_38]
    .text:0100130E                mov    [ebp+var_14], eax
    .text:0100130E
    .text:01001311
    .text:01001311 loc_1001311:                         
    .text:01001311                cmp    [ebp+pSid], ebx
    .text:01001314                jz      short loc_100131F
    .text:01001314
    .text:01001316                push    [ebp+pSid]      ; pSid
    .text:01001319                call    ds:FreeSid
    .text:01001319
    .text:0100131F
    .text:0100131F loc_100131F:                         
    .text:0100131F                                       
    .text:0100131F                push    [ebp+hObject]  ; hObject
    .text:01001322                call    ds:CloseHandle
    .text:01001328                call    ds:RevertToSelf ; Terminate the impersonation
    .text:01001328                                        ; of a client application
    .text:0100132E                cmp    [ebp+var_14], ebx
    .text:01001331                jz      loc_10013DB
    .text:01001331
    .text:01001337                jmp    short loc_100133F
    .text:01001337
    .text:01001339 ; ---------------------------------------------------------------------------
    .text:01001339
    .text:01001339 loc_1001339:                         
    .text:01001339                call    ds:RevertToSelf ; Terminate the impersonation
    .text:01001339                                        ; of a client application
    .text:01001339
    .text:0100133F
    .text:0100133F loc_100133F:                         
    .text:0100133F                                       
    .text:0100133F                lea    eax, [ebp+var_48]
    .text:01001342                push    eax
    .text:01001343                push    edi
    .text:01001344                lea    eax, [ebp+var_44]
    .text:01001347                push    eax
    .text:01001348                push    ebx
    .text:01001349                push    edi
    .text:0100134A                or      esi, 10000000h
    .text:01001350                push    esi
    .text:01001351                mov    [ebp+var_44], 10010h
    .text:01001358                call    ds:NtRaiseHardError
    .text:0100135E                mov    esi, eax
    .text:01001360                call    LsaISetupWasRun
    .text:01001360
    .text:01001365                test    al, al
    .text:01001367                jz      short loc_10013B4 ; 关闭计算机
    .text:01001367
    .text:01001369                push    offset s_Setup_failed ; "\\SETUP_FAILED"
    .text:0100136E                lea    eax, [ebp+var_40]
    .text:01001371                push    eax
    .text:01001372                call    ds:RtlInitUnicodeString
    .text:01001378                lea    eax, [ebp+var_40]
    .text:0100137B                mov    [ebp+var_2C], eax
    .text:0100137E                lea    eax, [ebp+var_34]
    .text:01001381                push    eax
    .text:01001382                push    100002h
    .text:01001387                lea    eax, [ebp+var_10]
    .text:0100138A                push    eax
    .text:0100138B                mov    [ebp+var_34], 18h
    .text:01001392                mov    [ebp+var_30], ebx
    .text:01001395                mov    [ebp+var_28], ebx
    .text:01001398                mov    [ebp+var_24], ebx
    .text:0100139B                mov    [ebp+var_20], ebx
    .text:0100139E                call    ds:NtOpenEvent
    .text:010013A4                test    eax, eax
    .text:010013A6                jl      short loc_10013DB
    .text:010013A6
    .text:010013A8                push    ebx
    .text:010013A9                push    [ebp+var_10]
    .text:010013AC                call    ds:NtSetEvent
    .text:010013B2                jmp    short loc_10013DB
    .text:010013B2
    .text:010013B4 ; ---------------------------------------------------------------------------
    .text:010013B4
    .text:010013B4 loc_10013B4:                         
    .text:010013B4                cmp    esi, ebx
    .text:010013B6                jl      short loc_10013DB
    .text:010013B6
    .text:010013B8                mov    esi, ds:RtlAdjustPrivilege
    .text:010013BE                lea    eax, [ebp+var_14]
    .text:010013C1                push    eax
    .text:010013C2                push    ebx
    .text:010013C3                push    edi
    .text:010013C4                push    13h
    .text:010013C6                call    esi ; RtlAdjustPrivilege
    .text:010013C8                push    edi            ; edi == 2 ?
    .text:010013C9                call    ds:NtShutdownSystem
    .text:010013CF                lea    eax, [ebp+var_14]
    .text:010013D2                push    eax
    .text:010013D3                push    ebx
    .text:010013D4                push    [ebp+var_14]
    .text:010013D7                push    13h
    .text:010013D9                call    esi ; RtlAdjustPrivilege
    .text:010013D9
    .text:010013DB
    .text:010013DB loc_10013DB:                         
    .text:010013DB                                       
    .text:010013DB                                       
    .text:010013DB                                       
    .text:010013DB                                       
    .text:010013DB                                       
    .text:010013DB                mov    ecx, [ebp+var_4]
    .text:010013DE                pop    edi
    .text:010013DF                pop    esi
    .text:010013E0                pop    ebx
    .text:010013E1                call    sub_10015C5
    .text:010013E1
    .text:010013E6                leave
    .text:010013E7                retn    4
    .text:010013E7
    .text:010013E7 sub_10011EE    endp
下面是lsass.exe的部分代码。俺写得不伦不类。哎,继续加强俺的汇编功底。代码:
    ;--------------------------------------------------------
    ;
    ;code By Asm QQ:448761813
    ;
    ;---------------------------------------------------------
    .386
    .model flat, stdcall
    option casemap:none
    ;--------------------------------------------------------
    ;
    ;未编写完成的lsass.exe的代码,就算写完,估计还需要大面积调式
    ;所以这里不好把头文件和库写出。不过我们总算了解一点东西,
    ;就是为什么结束了lsass.exe,系统会关机。原来是调用NtRaiseHardError
    ;来检查错误,发现了,就调用NtShutdownSystem。
    ;
    ;----------------------------------------------------------
    .data
    dword_1003004 dd 0BB40h
    .const
    CCOUNTED_UNICODE_STRING    "\\SAM_SERVICE_STARTED",g_usSam, 4
    .code
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    Lsasses proc lpRet:LPSTR
    local hEvent1:HANDLE
    local hEvent:HANDLE
    local szTYPE:EVENT_TYPE
    local Message[1024]:DWORD
    local Error:HARDERROR_RESPONSE_OPTION
    local Response:HARDERROR_RESPONSE
    local en:DWORD
    mov esi,lpRet
    xor ebx,ebx
    cmp esi,ebx
    mov hEvent1,eax
    push edi  ;edi是什么,还未知
    mov ebx,hEvent
    jl      loc_1001298
    invoke RtlInitUnicodeString,addr lpBuff,addr g_usSam
    invoke NtCreateEvent,hEvent,100002h,CTXT("LsassEvent"),szTYPE.SynchronizationEvent,sizeof szTYPE.SynchronizationEvent;这个函数的写得有点牵强
    .if eax>=ebx  ;ebx到底是什么?有待进一步分析!
    invoke NTSetEvent,hEvent,ebx
    .elseif eax==40000000h
    invoke NtOpenEvent,hEvent,100002h,CTXT("LsassEvent")
    .elseif eax
    invoke NtClose,hEvent
    .endif
    loc_1001298:
                invoke ImpersonateSelf,2
                xor edi,edi
                inc edi
                .if eax==NULL
                jmp loc_100133F
                .endif
    loc_100133F: 
              or  esi, 10000000h
              invoke NtRaiseHardError,esi,edi,ebx,addr Message,addr Error,addr Response
              mov esi,eax ;esi是在堆栈中,这里典型的通过寄存器传递参数
              call LsaISetupWasRun
              test al,al
              jz NtShutdown
    NtShutdown:
              invoke RtlAdjustPrivilege,SE_SHUTDOWN_PRIVILEGE,2,2,addr en
              invoke NtShutdownSystem,2
              invoke RtlAdjustPrivilege,SE_SHUTDOWN_PRIVILEGE,addr en,2,addr en
    ret
    Lsasses endp
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    loc_10013EF proc
    local Handel:HANDLE
    local dwRet:DWORD
    invoke SetErrorMode,SEM_FAILCRITICALERRORS
    invoke SetUnhandledExceptionFilter,EXCEPTION_ACCESS_VIOLATION
    invoke NtSetInformationProcess,0FFFFFFFFh,5,addr Handel,4
    .if eax<NULL
    mov dwRet,eax
    jmp loc_1001486
    .endif
    loc_1001486:
              invoke Lsasses,dwRet ;执行完这个函数,还不知道到底是做了什么的。
              invoke ExitThread,0
    loc_10013EF endp
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    DriverEntry proc pDriverObject:PDRIVER_OBJECT, pusRegistryPath:PUNICODE_STRING
    invoke  loc_10013EF;调用第一个子函数,姑且这么写
    mov eax,STATUS_DEVICE_CONFIGURATION_ERROR
    ret
    DriverEntry endp
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    end DriverEntry
怀上了。。哈哈~