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

文章作者: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

test.sys.rar (2 K)

相关日志

抢楼还有机会... 抢座Rss 2.0或者 Trackback

发表评论