图解恶意样本分析的常用方法,你与安全专家的差距只有一篇文章!
文件识别
常见的可执行程序格式有PE,ELF,MACH-O等,不同的格式有不同的标志信息(参考理论篇),知道了目标文件的格式后才能确定对应的分析方法和分析工具。
可以使用16进制解析器载入可执行程序,然后查看是哪种类型的文件。
图:PE文件格式
图:ELF文件格式
一般二进制文件的前四个字节为文件格式的magic,可以通过从网络搜索获得文件的信息,或者使用相关的工具(PEID,file)等进行自动识别。
静态分析
静态分析技术通常是研究恶意代码的第一步。静态分析指的是分析程序指令与结构来确定目标程序的功能的过程。在这个时候,病毒本身并不在运行状态。我们一般采用以下几种方式进行静态分析:
采用反病毒引擎扫描
如果尚不确定目标程序是否为病毒程序,我们可以首先采用多个不同的反病毒软件来扫描一下这个文件,看是否有哪个引擎能够识别它。(www.virscan.org、www.virustotal.com )
注意:只能通过MD5值查询,不允许将样本进行上传。
图 35:VitusTotal检测结果界面
计算哈希值
哈希是一种用来唯一标识目标程序的常用方法。目标程序通过一个哈希算法,会产生出一段唯一的用于标识这个样本的哈希值,我们可以将这个值理解为是目标程序的指纹。常用的哈希算法有MD5、Sha-1以及CRC32等。由于仅仅采用一种算法,特别是MD5算法,有可能使得不同程序产生同样的哈希结果,所以一般会运用多种哈希验证文件的唯一性。
图 36:计算文件校验码
查找字符串
程序中的字符串就是一串可打印的字符序列,一个程序通常都会包含一些字符串,比如打印输出信息、连接的URL,或者是程序所调用的API函数等。从字符串中进行搜索是获取程序功能提示的一种简单方法。(在IDA和OD中都可以查找字符串)并不是所有的字符串都是有意义的,但是利用这个结果,也能够给我们的静态分析带来很大的便利了。
图 37:查看字符串信息
查找导入函数
如果软件被加壳的话,那么导入表中的函数会很少,所以可以从这里判断文件是否被加壳。如果没有加壳,那么导入表中会列出程序使用的大部分函数(除去程序动态获得的),我们就可以通过这些函数大致判断一下程序的行为。
解析宏
使用IDA反汇编程序的时候,IDA并不会将宏的名字解析出来,相反,它只会使用宏对应的数字进行显示,如下如所示:
如果只看这些数字,完全无法得知什么情况,好在IDA提供了解析机制,可以将数字转换为宏名。在对应的数字上右键,选择Enum:
然后在弹出的对话框中选择对应的宏即可!
替换后的结果如下,这样的话,就方便了静态查看代码。
侦壳操作
病毒木马编写者经常会使用加壳技术来让他们的恶意程序难以被检测或分析。正常的程序总是会包含很多字符串。而加了壳的恶意代码通过分析所得到的可打印字符串就会很少。如果查找出的程序的字符串很少时,那么这个程序就很有可能是加了壳的。此时往往就需要使用其它方法来进一步检测它们的行为。(常用PEiD进行查壳)
图 38:查壳
动态调试
使用调试器对病毒进行分析在反病毒工作中扮演着十分重要的角色。调试器允许你查看任意内存地址的内容、寄存器的内容以及每个函数的参数。调试器也允许你在任意时刻改变关于程序执行的任何东西。比如你可以在任意时刻改变一个变量的值——前提是你需要获得关于这个变量足够的信息,包括在内存中的位置。在实际的动态调试过程中,最常用的是OllyDBG和WinDbg,前者是病毒分析人员使用最多的调试器,缺点是不支持内核调试,如果想调试内核,WinDbg基本上就是唯一的选择了。虽然IDA Pro也能够进行动态调试,但是它远远不如OD方便。因此在实际分析的过程中,往往是将二者结合使用的。因为如果用IDA Pro在静态分析中遇到了十分抽象的函数,那么用OD动态地执行一下,该函数的功能往往就能一目了然了。关于常用工具OllyDbg和Windbg的使用方法请参考工具篇。
脱壳
攻击者为了保护攻击代码,提高分析难度,避免被杀毒软件查杀,经常对可执行程序进行加壳来达到以上目的,本节对一些常见的壳的脱壳方法进行介绍(关于壳的基本信息可以参考文件封装篇)。
UPX
将UPX加壳程序使用OD打开时出现下面的对话框,选择“否”。
单步跟踪法
单步跟踪法的原则是实现向下的跳转,越过向上的跳转,如果越过了某一个向上的跳转后,程序跑飞了,那么再次调试到那个跳转语句的时候就实现其跳转,然后再按照实现向下跳转,忽略向上跳转的原则进行调试。
如上图所示,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。至此,脱壳完毕。
ESP定律法
关键句运行之后,ESP的值会改变!
右键ESP,选择Follow in Dump。
在ESP地址处设置硬件访问断点。
设置完断点之后,可以选择Debug->Hardware breakpoints查看硬件断点是否设置成功。
F9运行程序,程序停在关键句附近,接着要删除设置的硬件断点,直接店家上图所示的Delete即可。找到OEP之后再进行脱壳。
内存镜像法
首先需要对OD进行设置,忽略所有异常
在内存窗口中找到程序的.rsrc段,按f2键设置断点,shift+f9运行程序,断下之后,在程序的代码段按f2设置断点。
shift+f9运行,程序将停在OEP附近。
ASPack
脱ASPack壳可以使用上面所说的单步跟踪法,ESP定律法和内存镜象法,这里以单步跟踪法进行演示,其他两种方法的思路如上所述。
单步跟踪法
单步跟踪法除了上面说的跳转规则外,还有一个规则需要遵从,那就是近call f7进入,远call f8跳过。如果跳过了某个函数之后程序跑飞,那么再次调试时f7进入此函数即可。
如下所示,载入程序后即可看到一个call指令,那么这个函数就需要进入跟踪。
接着按照跳转指令和call指令规则进行跟踪。
跟踪到如上图所示的地址后,就快到大OEP了,可见这个程序采用的是push/ret的方式进行跳转的,而且跳转的跨度很到,从0x004243BA处跳转到0x00402360。跳转之后即到OEP,接着按照上面所说的方式进行脱壳。
FSG
单步跟踪法
按照前面讲解的原则对fsg壳进行单步跟踪需要细心,拿此例来说,单步跟踪的时候,看到如下所示的语句:
这个跳转并没有实现,但是程序的OEP就在0x004010CC,我们可以跟随到这个地址里面查看代码,直接在这个地址右键,选择follow:
但是并没有看到我们想要的代码:
遇到这种情况,直接右键,选择Analysis->Analyse code,就可以将这些机器码转为汇编码:
ESP定律法
使用ESP定律法单步跟踪的时候,要时刻注意着ESP值的变化,当ESP的值发生变化后,就安装上面所说的方法设置硬件访问断点,然后运行程序,程序将停止在oep附近,然后在单步跟踪,很快就将找到程序OEP。
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掉即可。
PECompact1.84
使用单步跟踪法对PECompact壳进行调试的时候,会看到有些向上的跳转,如果我们在这些跳转的下面下断点运行程序的话,程序将跑飞,这个时候,就需要在这些跳转的前面,找一个没有实现的大跳转,跟随进去,设置断点,然后运行程序,使用这种方法,一般很快就可以找到OEP。
例如:
有一个向上的jmp跳转,如果在它下面设置断点并运行程序的话,程序就将跑飞,这时,需要重新载入程序,在这个jmp前面找到一个没有实现的大跳转。
跟随进这个跳转地址,设置断点运行程序
按照这个思路进行调试,即可找到程序OEP,接下来就可以进行脱壳。
nspack
对于nspack的壳,最简单的方法就是使用esp定律法,当然,使用前面所说的其他方法也可以找到OEP。
Yoda
内存镜像法
首先使用peid查看一下壳,可以看到是yoda1.2的壳
使用OD载入程序,忽略所有异常,找到内存的.rsrc段,设置断点后运行程序,然后再在代码段设置断点,运行程序,就可直接到达程序的OEP,脱这个壳的重点在于修复方面。按照上述方法进行脱壳,使用Import REConstructor进行修复,发现大部分的指针都是无效的。
点击Show Invalid显示无效指针,然后右键选择Trace Level1进行修复。
修复之后,所有的指针都有效了
然后再选择目标程序进行fix dump。
还有一个方法是单独寻找,比如在如下图所示的情况下:
右键目标指针,选择16进制查看。
我们选择的指针就是第一行那个,库文件是advapi32,函数名为RegSetValueExA:
然后双击刚才选择的指针,查找对应的动态库和函数名
点击OK之后,就会发现指针已被修复。
当然这种方法适合无效指针较少的情况。修复完之后,选择脱壳后的文件进行Fix即可。
巧方法
打开OD,对OD进行设置。
选择SFX->Trace real entry bytewise。
然后载入目标程序,OD将自动停在OEP处。这种方法可以尝试使用,不保证适用于每一种壳。
附加数据的处理
有些加壳的作者会将一些关键的代码放到附加数据里,这样的话,当脱壳之后,附加数据里的代码也会被脱掉,这样就达到了保护代码的作用。这小节就来讲讲如何处理带有附加数据的情况。
首先使用peid对目标程序进行查壳,从peid的显示信息上看,可以看到这是北斗壳,Overlay表示有附加数据。
这个壳比较简单,重点讲解是脱壳后的修复,这里介绍两种方法。
第一种方法是使用16进制编辑器载入原始的目标程序,从数据末尾向上找,一直找到全为0的位置。
从CA00开始复制,一直复制到数据末尾,然后打开修复后的文件,在数据的末尾将复制的数据粘贴进去即可。
第二种方法和第一种类似,只是找的速度相对较快,使用peid查看程序的节信息。
我们需要关注的是R偏移和R大小,找最后一个区段,使用0x400+0xC600=0xCA00,然后在16进制查看器中定位到这个地址,即是我们复制的数据的开始地址。
多线程调试
OD调试软件时,它每次只能跟一个线程,如果遇到的软件创建了很多线程,那么调试起来就比较麻烦了,本节介绍一下多线程的调试方法。
首先看一下线程创建的函数:
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,//SD
SIZE_T dwStackSize,//initialstacksize
LPTHREAD_START_ROUTINE lpStartAddress,//threadfunction
LPVOID lpParameter,//threadargument
DWORD dwCreationFlags,//creationoption
LPDWORD lpThreadId//threadidentifier
)
重点看第三个和第四个函数,其中第三个参数指定了新线程的入口地址,第四个参数为新线程所需的参数,当程序调用此函数来创建线程的时候,定位到线程的入口地址设置断点,一般情况下,程序会在后面调用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文件后,原始内容如下
[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS=”Microsoft Windows XP Professional” /noexecute=optin /fastdetect
将最后一行复制并粘贴在[operating systems]下,然后修改一些参数即可
[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS=”XP Debug” /fastdetect /debug /debugport=com1 /buadrate=115200
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS=”Microsoft Windows XP Professional” /noexecute=optin /fastdetect
windbg配置
下面设置调试机上的windbg启动参数,使之连接一个管道,并把这个管道当作一个串口来处理,首先建立一个windbg.exe的快捷方式,然后右键快捷方式图标选择属性,在属性对话框的目标一栏加上空格后添加windbg.exe -b -k com:pipe,port=\\.\pipe\com_1,baud=115200,pipe,然后点击保存即可。
要进行双机调试的话,在虚拟机启动时,选择启动调试程序,当虚拟机启动起来之后,再开启windbg就可以连接到虚拟机中。
设置windows内核符号表
打开windbg,选择菜单“File”->”Symbol File Path”,然后填写:
srv*c:\Symbols*http://msdl.microsoft.com/download/symbols
如下图,如果我们选择了Reload,那么相当于输入了.reload命令,这时开始下载符号。
以上方法是设置是WinDbg自动用HTTP协议从微软的网站上下载所需的符号表。下载完后可以在C:\Symbols目录中查看,这个路径也可以指定为其它路径。
寻找DriverEntry
首先使用命令uf nt!IopLoadDriver查看驱动加载的入口,针对32位程序和64位程序,入口处的代码不一样,32位下的代码如下
nt!IopLoadDriver+0x663:
805a07c9 ffb570ffffff push dword ptr [ebp-90h]
805a07cf 57 push edi
805a07d0 ff572c call dword ptr [edi+2Ch]
805a07d3 3bc3 cmp eax,ebx
805a07d5 8b8d68ffffff mov ecx,dword ptr [ebp-98h]
805a07db 8945ac mov dword ptr [ebp-54h],eax
805a07de 8901 mov dword ptr [ecx],eax
805a07e0 0f8c91200500 jl nt!IopLoadDriver+0x67c (805f2877)
64位下的代码如下:
nt!IopLoadDriver+0x9fe:
fffff800`02cb545e 488bd6 mov rdx,rsi
fffff800`02cb5461 488bcb mov rcx,rbx
fffff800`02cb5464 ff5358 call qword ptr [rbx+58h]
fffff800`02cb5467 4c8b15da3bdaff mov r10,qword ptr [nt!PnpEtwHandle (fffff800`02a59048)]
fffff800`02cb546e 8bf8 mov edi,eax
fffff800`02cb5470 898424e0000000 mov dword ptr [rsp+0E0h],eax
fffff800`02cb5477 4c3bd5 cmp r10,rbp
fffff800`02cb547a 0f848e000000 je nt!IopLoadDriver+0xaae (fffff800`02cb550e)
可以通过搜索上述代码中加红的代码定位到关键点,然后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脚本进行一下美化,推荐美化网站:http://jsbeautifier.org/
下面进入正题,讲解js的调试方法。
Alert方法
在互联网刚刚起步的时代,网页前端还主要以内容展示为主,浏览器脚本还只能为页面提供非常简单的辅助功能的时候。那个时候,网页主要运行在以IE6为主的浏览器中,JS的调试功能还非常弱,只能通过内置于Window对象中的alert方法来调试,在网页中按F12键,点击Console按钮。
直接在这里输入想要查看的值即可。如下图所示,我们输入var a = ‘abc’;alert(a);浏览器即弹出对话框,显示变量a的值。
Console方法
随着js能做的事情越来越多,责任越来越大,地位也越来越重要,传统的alert调试方法渐渐的跟不上技术前进的节奏,alert调试方式弹出的调试信息,窗口不太美观,而且会遮挡页面内容,另外,使用alert方法,必须在程序逻辑中添加alert(xxx)的语句才能正常工作,比较麻烦,对于开发人员来说,后期还要手动清除这些代码。为了避免这种手续,出现了console的调试方法。
和alert方法类似,只是将语句换成console即可。
也可以在js恶意脚本中添加console语句,输出想要查看的目标值。
JS断点调试
JS断点调试,即是在浏览器开发者工具中为JS代码添加断点,让js执行到某一位置停止,方便我们对该处的代码进行分析和逻辑处理。为了方便说明,我们先准备一段示例代码:
使用sources断点
方法一:使用前面说的,在源码中添加alert或者console,添加后如下所示:
结果为:
这种方法需要我们手动添加代码,比较麻烦,下面就使用断点来调试
方法二:点击F12,找到sources菜单,在左侧树中找到对应的文件,然后点击行号来添加或删除断点
设置完断点后,刷新页面,程序将在断点处停下来,在sources界面中会看到当前作用域中所有的变量和值。
如果想一行一行的跟踪代码,可以使用浏览器提供的调试按钮:
这六个按钮的功能依次为:
Pause/Resume script execution:暂停/恢复脚本执行(程序执行到下一断点停止)。
Step over next function call:执行到下一步的函数调用(跳到下一行)。
Step into next function call:进入当前函数。
Step out of current function:跳出当前执行函数。
Deactive/Active all breakpoints:关闭/开启所有断点(不会取消)。
Pause on exceptions:异常情况自动断点设置
通过使用这几个键,就可以像调试可执行程序一样进行调试了。
需要注意的一点是,直接在代码区打印变量值的功能是在较新版本的Chrome浏览器中才新增的功能,如果你还在使用较老版本的Chrome浏览器,可能无法直接在断点的情况下查看变量信息,此时你可以将鼠标移动到变量名上短暂停顿则会出现变量值。也可以在右边Watch面板中输入变量值来查看,此方法同样适用于表达式。此外,你还可以在断点情况下,切换到Console面板,直接在控制台输入变量名称,回车查看变量信息。
debugger方法
这种方法是在源程序中添加“debugger;”语句,这样当代码执行到该语句的时候就会自动断下来,接下去的操作就和上面介绍的断点调试方法类似了。
.net调试
调试分析.net程序,首选的工具就是dnspy,这是一款集静态分析与动态调试于一体的强大工具。
直接使用dnspy打开目标应用程序,界面上显示的信息告诉了我们函数的入口点,直接点击Main即可进入到main函数处。
或者右键左边的树结构,在弹出对话框中选择Go to Entry Point也可以跳转到程序入口点。关于dnspy的详细使用方法,请参考工具篇的说明。
找到程序入口后,就可以在关键的地方设置断点(F9设置断点),然后选择菜单栏上的调试按钮开始调试。
点击上述按钮后,会弹出一个对话框,在对话框中选择要调试的程序和对应的参数就可以开始进行调试了。
如果程序没有经过混淆的话,dnspy基本可以解析处源码,所以.net的程序一般都是经过混淆的,如果知道它使用的混淆方法,可以在网上搜索对应的去混淆的工具,如果不知道的话,只有通过动态调试之后,自己对函数名或者变量名进行重命名,方法是在目标变量名或者函数名上右键选择Edit Method。
如果要修改类名的话,选择的是Edit Type。
在调试过程中,如果想要查看变量的值,直接将鼠标放到变量上就将显示变量的类型和值。