大夫 发表于 2011-8-11 09:12:43

分享逆向分析并重组源码的过程

又屈服在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



这里,我们已经构造出整个程序的结构。即:格式化打印信息-----分别调用三个子函数-------程序返回。这样一来,就可以重组出这个代码的框架:


Copy code
.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, ; 初始化OBJ_CASE_INSENSITIV
.text:0001027C                mov    dword ptr , 18h
.text:00010282                and    dword ptr , 0
.text:00010286                mov    dword ptr , 240h
.text:0001028D                and    dword ptr , 0
.text:00010291                mov    dword ptr , offset asc_10534 ; " /""
.text:00010298                and    dword ptr , 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,
.text:000102B0                push    eax            ; IoStatusBlock
.text:000102B1                lea    eax,
.text:000102B4                push    eax            ; ObjectAttributes
.text:000102B5                push    100000h      ; DesiredAccess
.text:000102BA                lea    eax,
.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    , 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    , 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        ; 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结构。这个结构是这样的:
ObjectAttributesOBJECT_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。


Copy code
.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, ; 这段是不是也很熟悉 :)
.text:00010325                mov    dword ptr , 18h
.text:0001032B                and    dword ptr , 0
.text:0001032F                mov    dword ptr , 240h
.text:00010336                and    dword ptr , 0
.text:0001033A                mov    dword ptr , offset s_24 ; "24"
.text:00010341                and    dword ptr , 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,
.text:00010359                push    eax            ; IoStatusBlock
.text:0001035A                lea    eax,
.text:0001035D                push    eax            ; ObjectAttributes
.text:0001035E                push    100000h      ; DesiredAccess
.text:00010363                lea    eax,
.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        ; 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


Copy code
.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,
.text:000103AD                mov    dword ptr , 18h
.text:000103B3                and    dword ptr , 0
.text:000103B7                mov    dword ptr , 240h
.text:000103BE                and    dword ptr , 0
.text:000103C2                mov    dword ptr , offset s_24 ; "24"
.text:000103C9                and    dword ptr , 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,
.text:000103DE                push    eax            ; IoStatusBlock
.text:000103DF                lea    eax,
.text:000103E2                push    eax            ; ObjectAttributes
.text:000103E3                push    100002h      ; DesiredAccess
.text:000103E8                lea    eax,
.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,
.text:00010410                push    eax            ; IoStatusBlock
.text:00010411                push    0            ; ApcContext
.text:00010413                push    0            ; ApcRoutine
.text:00010415                push    0            ; Event
.text:00010417                push        ; 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        ; 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 byasm
;
;-----------------------------------------------
.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,
.text:0100140E                push    eax
.text:0100140F                push    5
.text:01001411                push    0FFFFFFFFh
.text:01001413                mov    dword ptr , 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 ptr8 ;传递过来的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,
.text:01001200                xor    ebx, ebx
.text:01001202                cmp    esi, ebx
.text:01001204                mov    , eax
.text:01001207                push    edi
.text:01001208                mov    , ebx
.text:0100120B                jl      loc_1001298
.text:0100120B
.text:01001211                push    offset s_Sam_service_s ; "//SAM_SERVICE_STARTED"
.text:01001216                lea    eax, ; 由此可见,var_40 是一个局部缓冲区变量
.text:01001219                push    eax
.text:0100121A                call    ds:RtlInitUnicodeString
.text:01001220                push    ebx
.text:01001221                lea    eax,
.text:01001224                mov    , eax
.text:01001227                push    ebx
.text:01001228                lea    eax,
.text:0100122B                push    eax
.text:0100122C                mov    esi, 100002h
.text:01001231                push    esi
.text:01001232                lea    eax,
.text:01001235                push    eax
.text:01001236                mov    , 18h
.text:0100123D                mov    , ebx
.text:01001240                mov    , ebx
.text:01001243                mov    , ebx
.text:01001246                mov    , 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,
.text:01001264                push    eax
.text:01001265                push    esi
.text:01001266                lea    eax,
.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   
.text:0100127C                call    ds:NtSetEvent; 设置内核对象
.text:01001282                test    eax, eax
.text:01001284                jge    loc_10013DB
.text:01001284
.text:0100128A                push   
.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,
.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,
.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,
.text:010012D4                push    eax            ; pIdentifierAuthority
.text:010012D5                mov    , edi
.text:010012D8                mov    , ebx
.text:010012DB                mov    , bl
.text:010012DE                mov    , bl
.text:010012E1                mov    , bl
.text:010012E4                mov    , bl
.text:010012E7                mov    , bl
.text:010012EA                mov    , 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,
.text:010012FB                push    eax
.text:010012FC                push   
.text:010012FF                push   
.text:01001302                call    CheckTokenMembership
.text:01001302
.text:01001307                test    eax, eax
.text:01001309                jz      short loc_1001311
.text:01001309
.text:0100130B                mov    eax,
.text:0100130E                mov    , eax
.text:0100130E
.text:01001311
.text:01001311 loc_1001311:                        
.text:01001311                cmp    , ebx
.text:01001314                jz      short loc_100131F
.text:01001314
.text:01001316                push          ; pSid
.text:01001319                call    ds:FreeSid
.text:01001319
.text:0100131F
.text:0100131F loc_100131F:                        
.text:0100131F                                       
.text:0100131F                push    ; hObject
.text:01001322                call    ds:CloseHandle
.text:01001328                call    ds:RevertToSelf ; Terminate the impersonation
.text:01001328                                        ; of a client application
.text:0100132E                cmp    , 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,
.text:01001342                push    eax
.text:01001343                push    edi
.text:01001344                lea    eax,
.text:01001347                push    eax
.text:01001348                push    ebx
.text:01001349                push    edi
.text:0100134A                or      esi, 10000000h
.text:01001350                push    esi
.text:01001351                mov    , 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,
.text:01001371                push    eax
.text:01001372                call    ds:RtlInitUnicodeString
.text:01001378                lea    eax,
.text:0100137B                mov    , eax
.text:0100137E                lea    eax,
.text:01001381                push    eax
.text:01001382                push    100002h
.text:01001387                lea    eax,
.text:0100138A                push    eax
.text:0100138B                mov    , 18h
.text:01001392                mov    , ebx
.text:01001395                mov    , ebx
.text:01001398                mov    , ebx
.text:0100139B                mov    , 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   
.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,
.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,
.text:010013D2                push    eax
.text:010013D3                push    ebx
.text:010013D4                push   
.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,
.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
;
;---------------------------------------------------------
.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: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:
          oresi, 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
invokeloc_10013EF;调用第一个子函数,姑且这么写
mov eax,STATUS_DEVICE_CONFIGURATION_ERROR
ret
DriverEntry endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
end DriverEntry

cooby 发表于 2013-9-28 08:15:48

呵呵,我是进来帮顶一下的哈,辛苦了。。

cooby 发表于 2013-9-28 16:36:04

好东西啊,真是好东西,感谢楼主分享!谢谢!

cooby 发表于 2013-9-28 16:36:27

回答了那么多,没有加分了,郁闷。
页: [1]
查看完整版本: 分享逆向分析并重组源码的过程