恶意样本分析手册——常用方法篇

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

恶意样本分析⼿册——常⽤⽅法篇
⼀、⽂件识别
常见的可执⾏程序格式有PE,ELF,MACH-O等,不同的格式有不同的标志信息(参考理论篇),知道了⽬标⽂件的格式后才能确定对应的分析⽅法和分析⼯具。

可以使⽤16进制解析器载⼊可执⾏程序,然后查看是哪种类型的⽂件。

图:PE⽂件格式
图:ELF⽂件格式
⼀般⼆进制⽂件的前四个字节为⽂件格式的magic,可以通过从⽹络搜索获得⽂件的信息,或者使⽤相关的⼯具(PEID,file)等进⾏⾃动识别。

⼆、静态分析
静态分析技术通常是研究恶意代码的第⼀步。

静态分析指的是分析程序指令与结构来确定⽬标程序的功能的过程。

在这个时候,病毒本⾝并不在运⾏状态。

我们⼀般采⽤以下⼏种⽅式进⾏静态分析:
1. 采⽤反病毒引擎扫描
如果尚不确定⽬标程序是否为病毒程序,我们可以⾸先采⽤多个不同的反病毒软件来扫描⼀下这个⽂件,看是否有哪个引擎能够识别它。

(、 )
注意:只能通过MD5值查询,不允许将样本进⾏上传。

图:VitusTotal检测结果界⾯
2. 计算哈希值
哈希是⼀种⽤来唯⼀标识⽬标程序的常⽤⽅法。

⽬标程序通过⼀个哈希算法,会产⽣出⼀段唯⼀的⽤于标识这个样本的哈希值,我们可以将这个值理解为是⽬标程序的指纹。

常⽤的哈希算法有MD5、Sha-1以及CRC32等。

由于仅仅采⽤⼀种算法,特别是MD5算法,有可能使得不同程序产⽣同样的哈希结果,所以⼀般会运⽤多种哈希验证⽂件的唯⼀性。

图:计算⽂件校验码
3. 查找字符串
程序中的字符串就是⼀串可打印的字符序列,⼀个程序通常都会包含⼀些字符串,⽐如打印输出信息、连接的URL,或者是程序所调⽤的API函数等。

从字符串中进⾏搜索是获取程序功能提⽰的⼀种简单⽅法。

(在IDA和OD中都可以查找字符串)并不是所有的字符串都是有意义的,但是利⽤这个结果,也能够给我们的静态分析带来很⼤的便利了。

图:查看字符串信息
4. 查找导⼊函数
如果软件被加壳的话,那么导⼊表中的函数会很少,所以可以从这⾥判断⽂件是否被加壳。

如果没有加壳,那么导⼊表中会列出程序使⽤的⼤部分函数(除去程序动态获得的),我们就可以通过这些函数⼤致判断⼀下程序的⾏为。

5. 解析宏
使⽤IDA反汇编程序的时候,IDA并不会将宏的名字解析出来,相反,它只会使⽤宏对应的数字进⾏显⽰,如下如所⽰:
如果只看这些数字,完全⽆法得知什么情况,好在IDA提供了解析机制,可以将数字转换为宏名。

在对应的数字上右键,选择Enum:
然后在弹出的对话框中选择对应的宏即可!
替换后的结果如下,这样的话,就⽅便了静态查看代码。

6. 侦壳操作
病毒⽊马编写者经常会使⽤加壳技术来让他们的恶意程序难以被检测或分析。

正常的程序总是会包含很多字符串。

⽽加了壳的恶意代码通过分析所得到的可打印字符串就会很少。

如果查找出的程序的字符串很少时,那么这个程序就很有可能是加了壳的。

此时往往就需要使⽤其它⽅法来进⼀步检测它们的⾏为。

(常⽤PEiD进⾏查壳)
图:查壳
三、动态调试
使⽤调试器对病毒进⾏分析在反病毒⼯作中扮演着⼗分重要的⾓⾊。

调试器允许你查看任意内存地址的内容、寄存器的内容以及每个函数的参数。

调试器也允许你在任意时刻改变关于程序执⾏的任何东西。

⽐如你可以在任意时刻改变⼀个变量的值——前提是你需要获得关于这个变量⾜够的信息,包括在内存中的位置。

在实际的动态调试过程中,最常⽤的是OllyDBG和WinDbg,前者是病毒分析⼈员使⽤最多的调试器,缺点是不⽀持内核调试,如果想调试内核,WinDbg基本上就是唯⼀的选择了。

虽然IDA Pro也能够进⾏动态调试,但是它远远不如OD⽅便。

因此在实际分析的过程中,往往是将⼆者结合使⽤的。

因为如果⽤IDA Pro在静态分析中遇到了⼗分抽象的函数,那么⽤OD动态地执⾏⼀下,该函数的功能往往就能⼀⽬了然了。

关于常⽤⼯具OllyDbg和Windbg的使⽤⽅法请参考⼯具篇。

1. 脱壳
攻击者为了保护攻击代码,提⾼分析难度,避免被杀毒软件查杀,经常对可执⾏程序进⾏加壳来达到以上⽬的,本节对⼀些常见的壳的脱壳⽅法进⾏介绍(关于壳的基本信息可以参考⽂件封装篇)。

(1) UPX
将UPX加壳程序使⽤OD打开时出现下⾯的对话框,选择“否”。

(2) 单步跟踪法
单步跟踪法的原则是实现向下的跳转,越过向上的跳转,如果越过了某⼀个向上的跳转后,程序跑飞了,那么再次调试到那个跳转语句的时候就实现其跳转,然后再按照实现向下跳转,忽略向上跳转的原则进⾏调试。

如上图所⽰,jnz为向上的跳转,⽽且它的下⼀句代码也是向上的跳转,这时就需要在jmp的下⾯设置断点,直接让程序越过这两个跳转。

不能在下⾯的nop语句上f4运⾏到光标,否则程序会跑飞。

按照这套法则,很快就会找到关键句popad,那么程序的⼊⼝就在附近了。

如下图所⽰,并且再看程序的地址,jmp跳转的⽬标地址为0x004010CC,这条指令所在的地址为0x0040EA0F,可见这是⼀个很⼤的跳转,说明0x004010CC即是OEP。

(⼀般有很⼤的跳转的话,很快就会到达程序的OEP)
跳转之后,就到达程序OEP。

开始进⾏脱壳,这⾥使⽤OD插件进⾏脱壳,选择“插件”->”OllyDump”->”脱壳在当前调试进程”。

因为这⾥⼊⼝点地址正是我们的OEP:10CC,所以不需要修正,直接点击脱壳。

如果脱壳后的程序⽆法运⾏,还需要进⾏修正。

这⾥使⽤⽅式1脱壳之后,可以运⾏,不需要修正;使⽤⽅式2脱壳之后,⽆法运⾏,可以使⽤Import REConstructor进⾏修正。

在软件的下拉框中选中要进⾏脱壳的程序(这⾥使⽤的是upx.exe),然后修改OEP为我们找到的值:0x10CC。

点击AutoSearch或者GetImports获取导⼊函数,然后点击showinvalid显⽰⽆效的函数,没有的话就点击FixDump,选取要修正的应⽤程序,之后,会在应⽤程序所在的⽂件夹下⽣成⼀个原⽂件名加下划线的应⽤程序。

⽐如原始⽂件名为xxx.exe,那么Import REConstructor⽣成的⽂件名为xxx_.exe。

⾄此,脱壳完毕。

(3) ESP定律法
关键句运⾏之后,ESP的值会改变!
右键ESP,选择Follow in Dump。

在ESP地址处设置硬件访问断点。

设置完断点之后,可以选择Debug->Hardware breakpoints查看硬件断点是否设置成功。

F9运⾏程序,程序停在关键句附近,接着要删除设置的硬件断点,直接店家上图所⽰的Delete即可。

找到OEP之后再进⾏脱壳。

(4) 内存镜像法
⾸先需要对OD进⾏设置,忽略所有异常
在内存窗⼝中找到程序的.rsrc段,按f2键设置断点,shift+f9运⾏程序,断下之后,在程序的代码段按f2设置断点。

shift+f9运⾏,程序将停在OEP附近。

2. ASPack
脱ASPack壳可以使⽤上⾯所说的单步跟踪法,ESP定律法和内存镜象法,这⾥以单步跟踪法进⾏演⽰,其他两种⽅法的思路如上所述。

(1) 单步跟踪法
单步跟踪法除了上⾯说的跳转规则外,还有⼀个规则需要遵从,那就是近call f7进⼊,远call f8跳过。

如果跳过了某个函数之后程序跑飞,那么再次调试时f7进⼊此函数即可。

如下所⽰,载⼊程序后即可看到⼀个call指令,那么这个函数就需要进⼊跟踪。

接着按照跳转指令和call指令规则进⾏跟踪。

跟踪到如上图所⽰的地址后,就快到⼤OEP了,可见这个程序采⽤的是push/ret的⽅式进⾏跳转的,⽽且跳转的跨度很到,从0x004243BA处跳转到0x00402360。

跳转之后即到OEP,接着按照上⾯所说的⽅式进⾏脱壳。

3. FSG
(1) 单步跟踪法
按照前⾯讲解的原则对fsg壳进⾏单步跟踪需要细⼼,拿此例来说,单步跟踪的时候,看到如下所⽰的语句:
这个跳转并没有实现,但是程序的OEP就在0x004010CC,我们可以跟随到这个地址⾥⾯查看代码,直接在这个地址右键,选择follow:
但是并没有看到我们想要的代码:
遇到这种情况,直接右键,选择Analysis->Analyse code,就可以将这些机器码转为汇编码:
(2) ESP定律法
使⽤ESP定律法单步跟踪的时候,要时刻注意着ESP值的变化,当ESP的值发⽣变化后,就安装上⾯所说的⽅法设置硬件访问断点,然后运⾏程序,程序将停⽌在oep附近,然后在单步跟踪,很快就将找到程序OEP。

4. FSG变形壳
FSG变形壳在找OEP的⽅法和FSG的查找⽅法⼀样,只是在脱壳的时候有点区别,按照FSG的脱壳⽅法找到OEP之后,进⾏脱壳,使⽤OD的插件进⾏脱壳,发现程序⽆法运⾏,然后再对其导⼊表进⾏修正。

使⽤Import REConstructor载⼊⽬标程序,修改OEP,点击show Invalid会看到⼀些⽆效的程序。

在这些⽆效的程序上右键,选择cut thunks,接着点击Fix Dump选择我们脱下来的程序。

但是修正之后发现仍然⽆法运⾏,将修复后的程序使⽤OD载⼊,直接F9运⾏,看到OD中断到下图所⽰的位置:
第⼀种⽅法,将int 0x13使⽤nop覆盖:
第⼆种⽅法,将jle改为jmp强制跳转,越过int 0x13:
修改之后,保存⽂件,就可以运⾏了。

也可以使⽤16进制⼯具打开⽂件,找到相应的位置,修改数据并保存。

四、FSG2.0
使⽤ESP定律法和单步跟踪法结合可以很快找到程序的OEP,这⾥重点讲解脱壳后的修复问题。

使⽤Import REConstructor载⼊程序后,点击Get Import可以看到只有37个函数,这是很不正常的,⽽且没有⽆效的指针。

如果直接进⾏Fix Dump程序依然⽆法执⾏。

可以看到上图中IAT表的⼤⼩只有0x94,这是不对的,需要对IAT进⾏修复,这⾥介绍两种⽅法,第⼀种⽅法是通过OD,当我们找到OEP的时候,可以看到下图所⽰的情况:
函数GetCommandLineA所在的地址是0x4063E4,在dump窗⼝(左下窗⼝)中定位到这个函数的地址:
向上找,直到遇到⼀堆00,此时就找到了IAT表的开始地址,如下图所⽰,开始地址是0x004062E4。

然后在往后找,同样是找00,即IAT的结尾。

可以看到它结尾
的地址是0x00406E00。

所以IAT的⼤⼩为0x00406E00-0x004062E4=0xB1C,接着就把RVA和Size写⼊Import REConstructor中。

cut掉⽆效的函数指针,选取我们脱壳后的应⽤程序进⾏Dump即可。

第⼆种⽅法和第⼀种类似,都需要找到IAT的RVA进⾏修改,不同的是不需要计算Size的值,随便写⼀个⽐较⼤的值,⽐如0x1000就⾏,这样的话,肯定会有很多⽆效的函数指针,当我们查看这些⽆效指针的反汇编代码时,会提⽰ReadError。

这种情况下,直接把⽆效的指针cut掉即可。

1. PECompact1.84
使⽤单步跟踪法对PECompact壳进⾏调试的时候,会看到有些向上的跳转,如果我们在这些跳转的下⾯下断点运⾏程序的话,程序将跑飞,这个时候,就需要在这些跳转的前⾯,找⼀个没有实现的⼤跳转,跟随进去,设置断点,然后运⾏程序,使⽤这种⽅法,⼀般很快就可以找到OEP。

例如:
有⼀个向上的jmp跳转,如果在它下⾯设置断点并运⾏程序的话,程序就将跑飞,这时,需要重新载⼊程序,在这个jmp 前⾯找到⼀个没有实现的⼤跳转。

跟随进这个跳转地址,设置断点运⾏程序
按照这个思路进⾏调试,即可找到程序OEP,接下来就可以进⾏脱壳。

2. nspack
对于nspack的壳,最简单的⽅法就是使⽤esp定律法,当然,使⽤前⾯所说的其他⽅法也可以找到OEP。

3. Yoda
(1) 内存镜像法
⾸先使⽤peid查看⼀下壳,可以看到是yoda1.2的壳
使⽤OD载⼊程序,忽略所有异常,找到内存的.rsrc段,设置断点后运⾏程序,然后再在代码段设置断点,运⾏程序,就可直接到达程序的OEP,脱这个壳的重点在于修复⽅⾯。

按照上述⽅法进⾏脱壳,使⽤Import REConstructor进⾏修复,发现⼤部分的指针都是⽆效的。

点击Show Invalid显⽰⽆效指针,然后右键选择Trace Level1进⾏修复。

修复之后,所有的指针都有效了。

然后再选择⽬标程序进⾏fix dump。

还有⼀个⽅法是单独寻找,⽐如在如下图所⽰的情况下:
右键⽬标指针,选择16进制查看。

我们选择的指针就是第⼀⾏那个,库⽂件是advapi32,函数名为RegSetValueExA:
然后双击刚才选择的指针,查找对应的动态库和函数名
点击OK之后,就会发现指针已被修复。

当然这种⽅法适合⽆效指针较少的情况。

修复完之后,选择脱壳后的⽂件进⾏Fix即可。

(2) 巧⽅法
打开OD,对OD进⾏设置。

选择SFX->Trace real entry bytewise。

然后载⼊⽬标程序,OD将⾃动停在OEP处。

这种⽅法可以尝试使⽤,不保证适⽤于每⼀种壳。

(3) 附加数据的处理
有些加壳的作者会将⼀些关键的代码放到附加数据⾥,这样的话,当脱壳之后,附加数据⾥的代码也会被脱掉,这样就达到了保护代码的作⽤。

这⼩节就来讲讲如何处理带有附加数据的情况。

⾸先使⽤peid对⽬标程序进⾏查壳,从peid的显⽰信息上看,可以看到这是北⽃壳,Overlay表⽰有附加数据。

这个壳⽐较简单,重点讲解是脱壳后的修复,这⾥介绍两种⽅法。

第⼀种⽅法是使⽤16进制编辑器载⼊原始的⽬标程序,从数据末尾向上找,⼀直找到全为0的位置。

从CA00开始复制,⼀直复制到数据末尾,然后打开修复后的⽂件,在数据的末尾将复制的数据粘贴进去即可。

第⼆种⽅法和第⼀种类似,只是找的速度相对较快,使⽤peid查看程序的节信息。

我们需要关注的是R偏移和R⼤⼩,找最后⼀个区段,使⽤0x400+0xC600=0xCA00,然后在16进制查看器中定位到这个地址,即是我们复制的数据的开始地址。

五、多线程调试
OD调试软件时,它每次只能跟⼀个线程,如果遇到的软件创建了很多线程,那么调试起来就⽐较⿇烦了,本节介绍⼀下多线程的调试⽅法。

⾸先看⼀下线程创建的函数:
1. HANDLE CreateThread(
2.
3. LPSECURITY_ATTRIBUTES lpThreadAttributes,//SD
4.
5. SIZE_T dwStackSize,//initialstacksize
6.
7. LPTHREAD_START_ROUTINE lpStartAddress,//threadfunction
8.
9. LPVOID lpParameter,//threadargument
10.
11. DWORD dwCreationFlags,//creationoption
12.
13. LPDWORD lpThreadId//threadidentifier
14.
15. )
重点看第三个和第四个函数,其中第三个参数指定了新线程的⼊⼝地址,第四个参数为新线程所需的参数,当程序调⽤此函数来创建线程的时候,定位到线程的⼊⼝地址设置断点,⼀般情况下,程序会在后⾯调⽤Sleep或WaitForSingleObject函数,这样的话,程序的控制权就到了新线程⾥⾯。

如果程序没有调⽤Sleep或WaitForSingleObject函数,那么可以修改函数的代码,强制程序调⽤这两个函数,这样程序就转到新线程中执⾏。

另⼀种⽅法是修改程序的EIP,使其指向新线程⼊⼝,如果有参数的话,还要修改寄存器的值,使其指向参数地址,不过这种⽅法可能会造成寄存器内容不正确,环境异常,从⽽造成程序执⾏崩溃。

还有⼀种⽅法来调试多线程。

如果程序多次调⽤CreateThread,确定⼀个我们打算调试的线程,并让这个线程创建成功,当程序再调⽤CreateThread创建线程的时候,直接修改此函数,让它直接返回,这样就不会再创建线程了,我们就可以只调试⼀个线程。

六、调试⼦进程
有些样本并不是单独运⾏的,它在运⾏过程中可能会创建⼦进程来完成恶意功能,遇到这种情况,就需要进⼊⼦进程中进⾏调试。

如果⽗进程创建⼦进程时是以suspended的⽅式创建的,那么⽗进程会向⼦进程进⾏代码注⼊,写⼊之后会调⽤ResumeThread函数恢复⼦进程的运⾏。

遇到这种情况,要确定⽗进程写⼊代码的地址,当代码写⼊之后,调⽤ResumeThread恢复⼦进程运⾏前,附加到⼦进程中,在代码注⼊的地址下断点并F9让⼦进程运⾏。

这时再回到⽗进程中,运⾏函数ResumeThread,这样⼦进程就可以断在代码注⼊的地址了。

还有⼀种创建⼦进程的⽅式,就只是简单的开启⼀个⼦进程运⾏,这种情况⽐较简单,需要注意的⼀点就是⽗进程创建
⼦进程时传给⼦进程的参数,使⽤OD打开要运⾏的⼦进程,传⼊所需的参数即可开始调试。

PS:如果使⽤windbg调试的话,可以使⽤命令.childdbg 1开启⼦进程调试。

七、SYS调试
sys是驱动⽂件,相对于应⽤程序来说,它的调试难度稍微⼤⼀点,调试sys需要进⾏双机调试,⽽前提就是搭建双机调试的环境。

环境搭建
(1) 打开vmware中对应的虚拟机设置界⾯,如下图:
(2) 查看是否已经有端⼝存在,如果有的话需要移除,否则windbg与vmware连接不上,⽐如下图,就需要将打印机移除。

(3) 添加串⼝。

(4) 在硬件类型窗⼝中选择串⾏端⼝,并点击下⼀步。

(5) 在串⾏端⼝类型窗⼝下选择输出到命名管道,然后点击下⼀步。

(6) 指定插槽。

配置如下图所⽰,其中命名管道的com_1为管道名称,可以作改动,但是在⽤windbg进⾏连接的时候也要注意名字的⼀致,我这⾥保留默认名。

两台机器,⼀台为【该端是服务器】保留默认设置,最后⼀个下拉框选择【另⼀端是应⽤程序】。

最后注意吧【启动时连接】的复选框选上。

然后点击【完成】按钮即可完成配置。

(7) 完成串⾏端⼝添加。

⼋、配置虚拟机
打开虚拟机中windows的系统盘,找到boot.ini⽂件,如果不显⽰这个⽂件的话,在⽂件夹选项中设置为“显⽰所有⽂件”,“不隐藏系统保护⽂件”,然后就可以看到boot.ini⽂件了。

打开boot.ini⽂件后,原始内容如下
1. [boot loader]
2.
3. timeout=30
4.
5. default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
6.
7. [operating systems]
8.
9. multi(0)disk(0)rdisk(0)partition(1)\WINDOWS=”Microsoft Windows XP Professional” /noexecute=optin /fastdetect 将最后⼀⾏复制并粘贴在[operating systems]下,然后修改⼀些参数即可
1. [boot loader]
2.
3. timeout=30
4.
5. default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
6.
7. [operating systems]
8.
9. multi(0)disk(0)rdisk(0)partition(1)\WINDOWS=”XP Debug” /fastdetect /debug /debugport=com1 /buadrate=115200
10.
11. multi(0)disk(0)rdisk(0)partition(1)\WINDOWS=”Microsoft Windows XP Professional” /noexecute=optin /fastdetect 1. windbg配置
下⾯设置调试机上的windbg启动参数,使之连接⼀个管道,并把这个管道当作⼀个串⼝来处理,⾸先建⽴⼀个windbg.exe的快捷⽅式,然后右键快捷⽅式图标选择属性,在属性对话框的⽬标⼀栏加上空格后添加windbg.exe -b -k com:pipe,port=\\.\pipe\com_1,baud=115200,pipe,然后点击保存即可。

要进⾏双机调试的话,在虚拟机启动时,选择启动调试程序,当虚拟机启动起来之后,再开启windbg就可以连接到虚拟机中。

2. 设置windows内核符号表
打开windbg,选择菜单“File”->”Symbol File Path”,然后填写:
1. srv*c:\Symbols*/download/symbols
如下图,如果我们选择了Reload,那么相当于输⼊了.reload命令,这时开始下载符号。

以上⽅法是设置是WinDbg⾃动⽤HTTP协议从微软的⽹站上下载所需的符号表。

下载完后可以在C:\Symbols⽬录中查看,这个路径也可以指定为其它路径。

3. 寻找DriverEntry
⾸先使⽤命令uf nt!IopLoadDriver查看驱动加载的⼊⼝,针对32位程序和64位程序,⼊⼝处的代码不⼀样,32位下的代码如下
1. nt!IopLoadDriver+0x663:
2.
3. 805a07c9 ffb570ffffff push dword ptr [ebp-90h]
4.
5. 805a07cf 57 push edi
6.
7. 805a07d0 ff572c call dword ptr [edi+2Ch]
8.
9. 805a07d3 3bc3 cmp eax,ebx
10.
11. 805a07d5 8b8d68ffffff mov ecx,dword ptr [ebp-98h]
12.
13. 805a07db 8945ac mov dword ptr [ebp-54h],eax
14.
15. 805a07de 8901 mov dword ptr [ecx],eax
16.
17. 805a07e0 0f8c91200500 jl nt!IopLoadDriver+0x67c (805f2877)
64位下的代码如下:
1. nt!IopLoadDriver+0x9fe:
2.
3. fffff80002cb545e 488bd6 mov rdx,rsi
4.
5.
6. fffff80002cb5461 488bcb mov rcx,rbx
7.
8. fffff80002cb5464 ff5358 call qword ptr [rbx+58h]
9.
10.
11. fffff80002cb5467 4c8b15da3bdaff mov r10,qword ptr [nt!PnpEtwHandle (fffff80002a59048)]
12.
13.
14. fffff80002cb546e 8bf8 mov edi,eax
15.
16. fffff80002cb5470 898424e0000000 mov dword ptr [rsp+0E0h],eax
17.
18.
19. fffff80002cb5477 4c3bd5 cmp r10,rbp
20.
21. fffff80002cb547a 0f848e000000 je nt!IopLoadDriver+0xaae (fffff80002cb550e)
可以通过搜索上述代码中加红的代码定位到关键点,然后bp下断点,之后输⼊”g”让虚拟机运⾏,回到使⽤软件KmdManager加载驱动,打开KmdManager,界⾯如下:
将sys⽂件拖⼊上图所⽰的窗⼝中,在⼩⽅框中打勾(可以在卸载驱动的时候再在下⾯的打勾),如下图所⽰:
然后点击Reg`nRun加载驱动,会看到断点断在我们设置的地⽅,然后F11进⼊就达到了DriverEntry开始调试。

注意:32位的驱动程序要在32位系统下调试,64的驱动程序要在64位系统下调试。

九、DLL调试
使⽤OD调试动态库时有两种打开⽅式,第⼀种⽐较简单,直接将dll⽂件拖⼊OD即可,OD⾃⾝会⾃动识别出来当前⽂件是动态库⽂件,然后启⽤loadll.exe来加载此动态库⽂件。

另⼀种⽅法是通过OD打开rundll32.exe,传⼊动态库⽂件的路径作为参数来进⾏调试。

上⾯两种是⽐较直接的⽅式,但是有的dll⽂件会在od载⼊并断下来时,就已经执⾏完了恶意代码,遇到这种情况,就需要下⾯介绍的⼀种调试技巧。

选择菜单栏的Options->Debugging options。

在弹出的窗⼝中选择Events,勾选Break on new module(dll).然后点击OK。

这样的话,在新模块载⼊的时候,OD会断下来。

此时注意Executable modules窗⼝的变化,这⾥会显⽰动态库加载的内存地址。

如图所⽰,我们的⽬标动态库的基地址是0x10000000。

然后使⽤IDA打开⽬标⽂件,找到想要下断点的地址,以下图为例:
假如我们想要在sub_1000824C处设置断点,直接在OD中,定位到这个地址,然后设置断点即可。

如果在IDA中显⽰的地址是0x2000824C,那么我们在OD中的0x2000824C地址处是找不到对应的代码的。

这时需要计算代码的偏移,很明显,我们可以知道这个地址的RVA是824C,然后在OD中,将这个偏移加上OD加载的基地址0x10000000即可得到对应代码的绝对地址。

然后设置断点运⾏程序即可(此时可以取消先前设置的Break on new module断点了)。

⼗、JS调试
⽬前使⽤JS来执⾏恶意功能或者下载恶意组件的情况已经很平常了,所以这⾥介绍⼀下关于js的调试⽅法。

⼤部分的js脚本都是经过混淆或者加密的,静态分析的话根本不可能,⼀般在分析之前都需要对js脚本进⾏⼀下美化,推荐美化⽹站:/
下⾯进⼊正题,讲解js的调试⽅法。

1. Alert⽅法
在互联⽹刚刚起步的时代,⽹页前端还主要以内容展⽰为主,浏览器脚本还只能为页⾯提供⾮常简单的辅助功能的时候。

那个时候,⽹页主要运⾏在以IE6为主的浏览器中,JS的调试功能还⾮常弱,只能通过内置于Window对象中的alert ⽅法来调试,在⽹页中按F12键,点击Console按钮。

直接在这⾥输⼊想要查看的值即可。

如下图所⽰,我们输⼊var a = ‘abc’;alert(a);浏览器即弹出对话框,显⽰变量a的值。

2. Console⽅法
随着js能做的事情越来越多,责任越来越⼤,地位也越来越重要,传统的alert调试⽅法渐渐的跟不上技术前进的节
奏,alert调试⽅式弹出的调试信息,窗⼝不太美观,⽽且会遮挡页⾯内容,另外,使⽤alert⽅法,必须在程序逻辑中添加alert(xxx)的语句才能正常⼯作,⽐较⿇烦,对于开发⼈员来说,后期还要⼿动清除这些代码。

为了避免这种⼿续,出现了console的调试⽅法。

和alert⽅法类似,只是将语句换成console即可。

也可以在js恶意脚本中添加console语句,输出想要查看的⽬标值。

3. JS断点调试
JS断点调试,即是在浏览器开发者⼯具中为JS代码添加断点,让js执⾏到某⼀位置停⽌,⽅便我们对该处的代码进⾏分
析和逻辑处理。

为了⽅便说明,我们先准备⼀段⽰例代码:
4. 使⽤sources断点
⽅法⼀:使⽤前⾯说的,在源码中添加alert或者console,添加后如下所⽰:
结果为:
这种⽅法需要我们⼿动添加代码,⽐较⿇烦,下⾯就使⽤断点来调试
⽅法⼆:点击F12,找到sources菜单,在左侧树中找到对应的⽂件,然后点击⾏号来添加或删除断点
设置完断点后,刷新页⾯,程序将在断点处停下来,在sources界⾯中会看到当前作⽤域中所有的变量和值。

如果想⼀⾏⼀⾏的跟踪代码,可以使⽤浏览器提供的调试按钮:
这六个按钮的功能依次为:
1. Pause/Resume script execution:暂停/恢复脚本执⾏(程序执⾏到下⼀断点停⽌)。

2. Step over next function call:执⾏到下⼀步的函数调⽤(跳到下⼀⾏)。

3. Step into next function call:进⼊当前函数。

4. Step out of current function:跳出当前执⾏函数。

5. Deactive/Active all breakpoints:关闭/开启所有断点(不会取消)。

6. Pause on exceptions:异常情况⾃动断点设置
通过使⽤这⼏个键,就可以像调试可执⾏程序⼀样进⾏调试了。

需要注意的⼀点是,直接在代码区打印变量值的功能是在较新版本的Chrome浏览器中才新增的功能,如果你还在使⽤较⽼版本的Chrome浏览器,可能⽆法直接在断点的情况下查看变量信息,此时你可以将⿏标移动到变量名上短暂停顿则会出现变量值。

也可以在右边Watch⾯板中输⼊变量值来查看,此⽅法同样适⽤于表达式。

此外,你还可以在断点情况下,切换到Console⾯板,直接在控制台输⼊变量名称,回车查看变量信息。

5. debugger⽅法
这种⽅法是在源程序中添加“debugger;”语句,这样当代码执⾏到该语句的时候就会⾃动断下来,接下去的操作就和上⾯介绍的断点调试⽅法类似了。

⼗⼀、.net调试
调试分析.net程序,⾸选的⼯具就是dnspy,这是⼀款集静态分析与动态调试于⼀体的强⼤⼯具。

直接使⽤dnspy打开⽬标应⽤程序,界⾯上显⽰的信息告诉了我们函数的⼊⼝点,直接点击Main即可进⼊到main函数处。

或者右键左边的树结构,在弹出对话框中选择Go to Entry Point也可以跳转到程序⼊⼝点。

关于dnspy的详细使⽤⽅法,请参考⼯具篇的说明。

找到程序⼊⼝后,就可以在关键的地⽅设置断点(F9设置断点),然后选择菜单栏上的调试按钮开始调试。

点击上述按钮后,会弹出⼀个对话框,在对话框中选择要调试的程序和对应的参数就可以开始进⾏调试了。

如果程序没有经过混淆的话,dnspy基本可以解析处源码,所以.net的程序⼀般都是经过混淆的,如果知道它使⽤的混淆⽅法,可以在⽹上搜索对应的去混淆的⼯具,如果不知道的话,只有通过动态调试之后,⾃⼰对函数名或者变量名进⾏重命名,⽅法是在⽬标变量名或者函数名上右键选择Edit Method。

如果要修改类名的话,选择的是Edit Type。

在调试过程中,如果想要查看变量的值,直接将⿏标放到变量上就将显⽰变量的类型和值。

跟着Jayson玩耍看世界,带你装逼带你飞。

喜欢的观众⽼爷可以点波关注,Jayson在此跪拜!投放⼴告为了养家糊⼝,谢谢⼤家的理解,嘻嘻!。

相关文档
最新文档