首页
社区
课程
招聘
[原创]如何写windbg高级脚本---以访问文件的windbg脚本为例说明
发表于: 2009-3-17 10:27 20561

[原创]如何写windbg高级脚本---以访问文件的windbg脚本为例说明

2009-3-17 10:27
20561

最近需要在访问指定文件时中断下来,但不知道如何下断,在网上搜索了一番无果,只好自己摸索了。听大侠说windbg的条件断点功能异常强大,可以实现,不禁心痒,特尝试一番,顺便熟悉一下windbg的脚本语法。

先来了解简单的,得到当前访问的文件名
先写段C代码,创建C:\a.txt并往文件中写任意几个字符,代码如下:
                HANDLE hFile=CreateFile("C:\\a.txt",
                        GENERIC_WRITE|GENERIC_READ,
                        0,
                        NULL,
                        OPEN_ALWAYS,
                        FILE_ATTRIBUTE_NORMAL,
                        NULL);
                if (hFile == INVALID_HANDLE_VALUE)
                {
                        return ;
                }
                char Buffer[]={"abcdefghijklemn"};
                DWORD dwReturn;
                WriteFile(hFile,Buffer,strlen(Buffer),&dwReturn,NULL);

                CloseHandle(hFile);
把以上代码放到对话框的按钮点击响应事件中去。编译链接得到test.Exe.
文件名为CreateFile API的第一个参数,因而在执行到该API的入口时,esp+4即表示第一个参数的地址。故可这样下断:
bp kernel32!CreateFileW "r $t1=poi(esp+4);.echo;.printf\"FileName:%mu\",$t1;.echo;g"

$t0~$t19为伪寄存器,可用来存储临时值,poi表示取地址的值,
也可将脚本保存为文件,然后在windbg中输入: $$><脚本文件路径 来运行。
我把以上脚本保存为 ”C:\script.txt”
用windbg打开以上代码编译得到的test.exe,
Ctrl+Break中断windbg,然后下断,即输入:$$><C:\script.txt,再输入g,让进程运行起来,
点击按钮,果其然,得到文件名了,见下图,



访问的文件获取了,那如何在访问指定文件时中断下来呢?字符串比较的脚本如何写呀?
上网查资料吧,不大一会,发现了$scmp/$sicmp/$spat是用来字符串操作的。$spat正合我意呀。
        $spat("string1”, "pattern”):判断参数1指定的字符串是否符合参数2指定的模式。模式字符串中可以包含?、*、#等特殊符号,WinDBG帮助文件中String Wildcard Syntax一节包含了详细的说明;
        这样摸索了一番,写了如下脚本:
bp kernel32!CreateFileW "
r $t1=poi(esp+4)
as /mu $FileName $t1
.echo
.printf\"File:%mu\",$t1
.echo
.block
{
.if($spat(\"${$FileName}\",\"*a.txt\"))
{
  .echo 'find...';
  ad ${/v:$FileName}
}
.else
{
  .echo no find...
  ad ${/v:$FileName}
  gc
}
}"

以上脚本,不复杂,实现当访问文件名类似“a.txt”时,windbg中断执行。

对脚本解析几个要点:
1.        使用伪寄存器,更快速的方法是在$前加上一个@符号。这样,WinDBG就知道@后面是一个伪寄存器,不需要搜索其他符号;
2.        r $t1=poi(esp+4),poi(esp+4)取地址的值,并赋给伪寄存器$t1 ;
3.        as /mu $FileName $t1 ,定义$t1 所指地址一个别名$FileName,用来在下面的$spat中使用。别名会在脚本加载时被解析程序替换一次。为何要用别名?你不用试试就知道了,直接用$t1不行,windbg提示你语法错误;
4.        .block是啥东西,看windbg帮助就知道了。代码块,如果需要每次运行进入替换,请用.block括起来;我这里有个别名,需要每次替换,所以用了个.block括起来;
5.        $spat为模式匹配函数,其他类似函数$scmp/$sicmp。
6.        ${$FileName}、${/v:$FileName}这呢?听我说来,${ aliase} 明确的指出了, 大括号 {} 内的变量名是可以被替换的,即使 aliase 和其它文本相连。如果要求 ${} 这个别名不被替换, 即不被解析程序替换成其他值, 只保留它当前的字面值.如下面的ad ${/v:$FileName},删除别名,此时用/v 选项来了阻止对该别名的替换, 保留它原来的字面值;
7.        别名用完记得要删除;删除方法用ad命令。
试试看看结果,在访问a.txt时断下来了。


如果我要在往该文件写数据时断下来,如何设断?直接在writeFile下断?但不知道当前访问的是哪个文件呀?在脚本里,通过文件句柄能得到相应的文件名吗?我反正还不知道,如果你知道请一定不要忘了告我呀?以下为我的脚本:
$$Written by shakesky
$$10:44 2009-2-12
$$访问文件之windbg下断脚本

bp kernel32!CreateFileW "
r $t0=poi(esp+4)
        as /mu $FileName $t0
.echo
.printf \"Prepare to visit file:%mu\",$t0
.echo
.block
{
        $$ 判断是否是访问我所需观察的文件
        .if($spat(\"${$FileName}\",\"*a.txt\"))
        {
                .echo 'Match...'
                ~.gu
                $$ 得到文件句柄
                r @$t1=eax
                .if(@$t1!=0xFFFFFFFF)
                {
                        $$往该文件写数据时下断
                        .printf \"File Handle:%08x\",$t1
                        .echo
                        bp kernel32!WriteFile \"
                        r @$t2=poi(esp+4)
                        .if(@$t2!=@$t1) {gc}
                        \"
                }
                ad ${/v:$FileName}
                gc
       
        }
        .else
        {
                .echo No Match...
                ad ${/v:$FileName}
                gc
        }
}
"
运行结果截图:


全文完,不当处请不吝指教。


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
  • 1.JPG (64.84kb,1616次下载)
  • 2.JPG (70.65kb,1580次下载)
  • 3.JPG (84.47kb,1125次下载)
收藏
免费 8
支持
分享
最新回复 (16)
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
好文,期待插件文档
2009-3-17 10:45
0
雪    币: 223
活跃值: (11)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
插件不会哦
2009-4-3 18:59
0
雪    币: 205
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
如果我要在往该文件写数据时断下来,如何设断?直接在writeFile下断?但不知道当前访问的是哪个文件呀?在脚本里,通过文件句柄能得到相应的文件名吗?我反正还不知道,如果你知道请一定不要忘了告我呀?

kernel debug--->bp NtWriteFile--->get FileHandle--->!handle filehandle get fileobj--->!fileobj getfilename--->end~~~
2009-10-29 17:20
0
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
不会使用插件啊,学习一下了
2009-11-2 09:10
0
雪    币: 73
活跃值: (70)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
不错不错..
2009-11-2 12:14
0
雪    币: 247
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
非常不错的文章
2009-11-2 12:21
0
雪    币: 219
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
好......
2009-11-2 16:47
0
雪    币: 392
活跃值: (89)
能力值: ( LV9,RANK:280 )
在线值:
发帖
回帖
粉丝
9
怎一个帅字了得
2009-12-7 09:31
0
雪    币: 384
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
灰常感谢~~~~
2010-11-21 13:14
0
雪    币: 29
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
正在学习windbg的用法。长见识了
2010-11-24 06:07
0
雪    币: 585
活跃值: (568)
能力值: ( LV13,RANK:290 )
在线值:
发帖
回帖
粉丝
12
不错,要是WINDBG做成OD那么友好的界面就好了,哎呀。。
2010-11-28 18:06
0
雪    币: 1115
活跃值: (122)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
13
为了提高逆向分析效率,其实应该注意做:
断点: CreateFileW, 条件: _arg1==L"Book1.xlsx"
或者:设置文件操作断点:打开文件"Book1.xlsx"
2010-11-28 21:54
0
雪    币: 33
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
这个断点好麻烦啊
2010-11-28 23:12
0
雪    币: 154
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
这种带别名的脚本不知道为啥被执行起来超级的龟速。。。
可以用这个程序:
int _tmain(int argc, _TCHAR* argv[])
{
while ( true )
{
MessageBoxW ( 0, L"11111111111111111", L"2222222222222222222", MB_OK );
}
return 0;
}

加脚本:
bp User32!MessageBoxW "
r $t1=poi(esp+8);
r $t2=poi(esp+c);
as /mu $Caption $t1;
as /mu $Title $t2;
.echo
.printf\"@@@:%mu,$$$:%mu\n\",$t1,$t2
.echo
.block
{
.if($spat(\"${$Caption} \",\"*aaaa*\")){ad ${/v:$Caption};ad ${/v:$Title}}
.else{ad ${/v:$Caption};;ad ${/v:$Title};gc}
}"
测试,可以发现windbg执行真的是超慢,而且还会卡住整个系统。。。
不是在下载符号表。。。
也不是在加载符号文件。。。
事先已经加载好符号表。。。
Ctrl+Alt+V么有显示什么东西。。。
相当困惑不解。。。
2011-1-11 15:39
0
雪    币: 188
活跃值: (85)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
16
崇拜。。。。。。
2011-1-12 15:25
0
雪    币: 1327
活跃值: (370)
能力值: ( LV11,RANK:190 )
在线值:
发帖
回帖
粉丝
17
写的好!
2011-1-12 16:12
0
游客
登录 | 注册 方可回帖
返回
//