Debug Blocker

  1. Debug Blocker技术是进程以调试模式运行自身或其他可执行文件的技术。
  2. DebugMe4程序应用了该技术,父进程DebugMe4.exe(PID12312)是调试器,子进程DebugMe4.exe是被调试者,两者分别执行不同的代码。

  3. 若重要代码运行于被调试进程,我么就必须调试它,但又由于调试器-被调试器关系具有反调试功能。
使用CreateProcess() API创建进程时,若选用了DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS参数,则创建出的父子进程会形成调试器与被调试器的关系。

反调试特征

  1. 父与子的关系
  • 调试器与被调试器关系中,调试进程与被调试进程首先是一种父子关系。
  1. 被调试进程不能在被其他调试器调试
  • Windows操作系统中,同一进程是无法同时被多个调试进程调试的,若想调试被调试进程,必须先切断原调试器与被调试者的关系。
  1. 终止调试进程的同时也终止被调试进程
  • 强制终止调试进程以切断调试器-被调试器关系时,被调试进程也会同时终止。
  1. 调试器操作被调试者的代码
  • Debug Blocker技术中,调试器用来操作被调试进程的运行分支,生成或修改执行代码等,并且,调试器会对被调试进程的代码运行情况产生持续影响,缺少调试进程的前提下,仅凭被调试进程无法正常运行。
  1. 调试器处理被调试进程中发生的异常
  • 调试者-被调试者关系中,被调试进程中发生的所有异常均有调试器处理。
  • 被调试进程中故意触发某个异常时,若该异常未得到处理,则代码将无法继续运行。
  • 被调试进程中发生异常时,进程会暂停,控制权转移到调试器,此时调试器可以修改被调试者的执行分支,此外也可以对被调试进程内部的加密代码解码,或者向寄存器、栈中存入某些特定值等。

调试练习:DebugMe4.exe

  1. 示例程序运行时,父进程会在控制台窗口输出字符串Parent Process,而子进程会在消息框中输出字符串“Child Process”。

第一次调试

  1. DebugMe4.exe是一个基于控制台的程序,查找程序的核心代码时经常使用的方法有:
  • 借助程序内部使用的字符串。
  • 预测程序中调用的Win32 API并设置断点。
  1. 使用OllyDbg打开DebugMe4.exe程序,调试运行到main()函数。
  • main()函数先调用CreateMutexW() API创建名称为“ReverSeCore:DebugMe4”的互斥对象(Mutex)。
00401009 CALL DWORD PTR DS:[408004];  CreateMutexW()
  • CreateMutexW()API正常返回后,调用GetLastError()获取Last Error,在将其与B7(ERROR_ALREADY_EXISTS)比较。
0040102A CALL DWORD PTR DS:[40801C] ; GetLastError()
00401030 CMP EAX,0B7
  • 通过互斥对象来检测进程是否重复运行,DebugMe4.exe作为父进程运行并正常创建名为“Reverse Core:Debug4”的互斥对象后,Last Error值为0,但其作为子进程运行时,由于父进程已经创建存在同名互斥体对象,所以Last Error值为B7.
  • 我们可以判断出DebugMe4.exe进程是以父进程形式运行,还是以子进程形式运行,若以父进程形式运行,则转到地址401037地址处,若以子进程形式运行,则转到0040103F地址处。
  • 由于当前以父进程形式运行,所以会调用401060地址处的函数,401060地址处的函数代码。
  • 跟踪进入401060函数,遇到调用CreateProcessW()函数的代码,该函数使用DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS参数创建自身进程,DebugMe4.exe以子进程形式运行自身进程,以Debug模式运行后,父进程为调试器,子进程为被调试者。
  1. 归纳
  • 通过名为“ReverseCore:DebugMe4"的互斥对象区分父进程与子进程。
  • 父子进程中存在执行分支代码(父进程:401037,子进程:40103F)
  • 父子进程的关系为调试器与被调试者的关系。

第二次调试

  1. 应用了Debug Blocker技术的程序中,核心代码一般都在子进程中运行。
  2. 操作基于互斥体的条件分支,调试要在子进程形式下运行的代码。
  3. 在OllyDbg中重启对DebugMe4.exe的调试,然后再401035地址处设置断点,运行DebugMe4.exe程序。
  • 右侧的Registers窗口中使用鼠标双击ZF,将其修改为1,然后执行401035地址处的JE指令,跳转到40103F地址处。
  • 查看40103F地址处的指令代码:
40103F 8DC0 LEA EAX, EAX
  • 执行以上指令就会触发ILLEGAL INSTRUCTION(非法指令)异常,表明指令错误。
  • LEA指令的第一个操作数为寄存器(r16/r32/r64),第二个操作数为内存,常见的LEA指令形式如下:
LEA EAX, DWORD PTR DS:[12FF48];
  • 地址12FF48就被存储到EAX寄存器,
  • 观察40103F地址处的指令(LEA EAX,EAX),其第二个操作数不是内存而是寄存器(EAX),导致指令格式发生错误。
  • 借助这些错误指令故意触发非法指令异常,在子进程中执行40103F地址处的错误指令时,就会触发非法指令异常,控制权将转移到父进程(调试器),获得控制权后后,父进程会处理子进程中发生的异常,同时还会做一些其他事情。
  • 从401041地址开始的指令,可以发现它们并不是正常的指令,看上去就像是加了密的代码。=> 猜想:父进程获取控制权后可能会使用这些指令对加密的代码解密,或者将执行分支修改为其他地址。
  1. Summary
  • 子进程的运行代码中存在故意触发异常的代码。
  • 后面代码为非正常代码(加密代码、数据、无意义的代码)。
  • 必须详细分析父进程的运行代码。

第三次调试

  1. 重启OllyDbg调试器,进入401060函数,调试运行到40115C地址处。
  • 401176地址调用了CreateProcessW() API,以调试模式运行自身进程(DebugMe4.exe),然后在4011CA地址处调用了WaitForDebugEvent() API,等待被调试进程发生Debug事件。
  • WaitForDebugEvent() API定义如下:
BOOL WINAPI WaitForDebugEvent(__out LPDEBUG_EVENT lpDebugEvent,__in  DWORD dwMilliseconds
);
  • 若调用WaitForDebugEvent() API,将在指定时间内等待被调试进程发生Debug事件,异常也是一种Debug事件,被调试进程发送异常时,将返回WaitForDebugEvent() API,然后,相关的异常信息就会填充到lpDebugEvent指针所指的DEBUG_EVENT结构体。
  • DEBUG_EVENT结构体:
typedef struct _DEBUG_EVENT { DWORD dwDebugEventCode; DWORD dwProcessId; DWORD dwThreadId; union { EXCEPTION_DEBUG_INFO Exception; CREATE_THREAD_DEBUG_INFO CreateThread; CREATE_PROCESS_DEBUG_INFO CreateProcessInfo; EXIT_THREAD_DEBUG_INFO ExitThread; EXIT_PROCESS_DEBUG_INFO ExitProcess; LOAD_DLL_DEBUG_INFO LoadDll; UNLOAD_DLL_DEBUG_INFO UnloadDll; OUTPUT_DEBUG_STRING_INFO DebugString; RIP_INFO RipInfo; } u;
} DEBUG_EVENT;
//dwDebugEventCode
#define EXCEPTION_DEBUG_EVENT 1
#define CREATE_THREAD_DEBUG_EVENT 2
#define CREATE_PROCESS_DEBUG_EVNT 3
#define EXIT_THREAD_DEBUG_EVENT 4
#define EXIT_PROCESS_DEBUG_EVENT 5
#define LOAD_DLL_DEBUG_EVENT 6
#define UNLOAD_DLL_DEBUG_EVENT 7
#define OUTPUT_DEBUG_STRING_EVENT 8
#define RIP_EVENT 9
  • dwDebugEventCode成员用来表示Debug事件类型,共有9种Debug事件,u成员保存着与各Debug事件对应的结构体(u成员为union类型,将9各结构体联合在一起)。
dwDebugEventCode = 1(EXCEPTION_DEBUG_EVENT)时,u.Exception成员会被保存起来;
dwDebugEventCode = 3(CREATE_PROCESS_DEBUG_EVENT)时,u.CreateProcessInfo即被保存下来。
  • 继续调试程序到4011CA地址处:
  • pDebugEvent所指地址为0019F9C0,然后按F8键执行4011CA地址处的指令,调用WaitForDebugEvent() API,然后查看0019F9C0中存储的值。
  • dwDebugEventCode值为3(CREATE_PROCESS_DEBUG_EVENT),它是被调试进程运行时最初发生的事件。
  • 4011F0地址处的MOV指令,[ESP+68]为0019F9C0,将该值传送到EAX寄存器后,再在4011F4地址处的指令中将其与1(EXCEPTION_DEBUG_EVENT)比较,由于当前dwDebugEventCode值为3,所以将执行4011F7地址处的JNZ指令,跳转到4012C0地址处。
  • 在4012C0地址处再次将EAX(dwDebugEventCode)值与5(EXIT_PROCESS_DEBUG_EVENT)比较,由于当前EAX值为3,所以跳过4012C3地址处的JE指令,继续执行。
  • 在4012D4地址处调用ContinueDebugEvent() API,继续运行处于被调试状态的被调试进程,然后再4012F2地址处的WaitForDebugEvent() API,进入等待状态,等待被调试进程发生Debug事件,再次发生Debug事件时,就转到4011F0地址处。
  • 4011F0~4011F7地址间的指令,该循环用来等待来自被调试者的EXCEPTION_DEBUG_EVENT(1)异常,只要集中调试这种情况就可以了,最简单的方法是,现在4011FD地址处设置断点F2,再按F9键运行,被调试者中发生EXCEPTION_DEBUG_EVENT(1)时,循环就会准确停在4011FD地址处。
  • 也可以再4011FD地址处设置条件记录断点,输出用户日志,然后根据条件停止运行。

第四次调试

  1. 借助OllyDbg的CLBP(条件记录断点)功能分析4011F0~4012FA地之间循环代码的执行流程。
  2. 首先输出被调试者发生的所有Debug事件,重启OllyDbg调试器后,通过Go To Expression命令转到4011F0地址处。
  3. 光标移动到4011F0地址处,按SHIFT+F4快捷键,打开设置CLBP对话框。
  • Condition项用来输入所需条件,上述条件表达式中,检测dwDebugEventCode是否为1(EXCEPTION_DEBUG_EVENT)。(0019F9C0表示DEBUG_EVENT结构体的起始地址,DWORD PTR DS:[0019F9C0]表示DEBUG_EVENT.dwDebugEventCode成员。
  • Explanation与Expression项用来输入要输出至Log窗口中的内容。
  • 将Pause program项设置为Never时,程序将会一直执行到最后,将Log value of expression项设置为Always,总是输出日志,不受指定条件的约束。
  • 在设置CLBP对话框中进行相应设置后,单击OK按钮,即在相应地址处(4011F0)设置好CLBP,显示为粉红色,BreakPoints窗口的Active栏中显示出Explanation项的内容。
  • 执行OllyDbg调试器中的Run命令,使DebugMe4.exe正常运行。
  • 观察输出日志可以看到,被调试进程中发生过3次EXCEPTION_DEBUG_EVENT(1).

第五次调试

  1. 集中调试EXCEPTION_DEBUG_EVENT(1)事件,重启OllyDbg调试器,在4011F0地址处设置CLBP。
  2. 在Pause program项中点选On condition,满足指定条件时,程序将暂停,在Log value of expression项中点选On condition,只有满足条件时,才会输出运行日志。
  3. 设置好CLBP后,按F9键执行OllyDbg的RUN命令,dwDebugEventCode=1(EXCEPTION_DEBUG_EVENT)时,程序将停在4011F0地址处,继续跟踪运行至4011FD地址处。
  • 代码中用到的内存地址如下:
[ESP+68] = [0019F9C0] = DEBUG_EVENT.dwDebugEventCode
[ESP+74] = [0019F9CC] = DEBUG_EVENT.EXCEPTION_DEBUG_INFO.EXCEPTION_RECORD.ExceptionCode
[ESP+80] = [0019F9D8] = DEBUG_EVENT.EXCEPTION_DEBUG_INFO.EXCEPTION_RECORD.ExceptionAddress
  • 这意味着当前被调试进程在770F1A62地址处发生了80000003(ExceptionCode-EXCEPTION_BREAKPOINT)异常,查看770F1A62可以看到,它是ntdll.dll模块的系统断点,程序以被调试者身份运行时,必定会触发该异常。
  • 系统断点并不是我们所关心的,按F9键继续运行程序。
EXCEPTION_DEBUG_INFO与EXCEPTION_RECORD结构体的定义如下:
typedef struct _EXCEPTION_DEBUG_INFO{EXCEPTION_RECORD ExceptionRecord;DWORD dwFirstChance;
} EXCEPTION_DEBUG_INFO, *LPEXCEPRTION_DEBUG_INFO;
typedef struct _EXCEPTION_RECORD {DWORD ExceptionCode;DWORD ExceptionFlags;struct _EXCEPTION_RECORD *ExceptionRecord;PVOID ExceptionAddress;DWORD NumberParameters;ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
}EXCEPTION_RECORD, *PEXEPTION_RECORD;
  1. EXCEPTION_ILLEGAL_INSTRUCTION(1)
  • 程序再次停在4011F0地址处。
  • 如图所示,ExceptionCode = C000001D(EXCEPTOION_ILLEGAL_INSTRUCTION),ExceptionAddress=0040103F,这表明被调试进程的40103F地址处发生了EXCEPTION_ILLEGAL_INSTRUCTION错误。
  • 第二次调试中,我们已经直到40103F地址处的指令为LEA EAX,EAX,这是条错误指令,被调试进程遇到40103F处的错误指令时,就会触发非法指令异常。
  • 若3个条件都满足,则执行40121D地址处的指令代码,只要有一个条件不满足,就跳转到其他地方。
  • 第一个EXCEPTION_ILLEGAL_INSTRUCTION异常发生后,就会执行40121D地址处的指令代码,并且出现一段很明显的代码,用来处理被调试进程中的异常并再次运行它。
  • 继续按F9键继续运行。
  1. EXCEPTION_ILLEGAL_INSTRUCTION(2)
  • 第三个EXCEPTION_DEBUG_EVENT发生于401048地址处,ExceptionCode与之前相同,为EXCEPTION_ILLEGAL_INSTRUCTION。
  • 401048地址处的指令并非正常形式的IA-32指令,看上去像是加密后的代码,401212~401217地址处的CMP/JNZ指令组合使程序执行跳转到401299地址处,也就是说,发生第二个EXCEPTION_ILLEGAL_INSTRUCTION异常后,会运行401299地址处的指令代码,在此状态下运行OllyDbg调试器的RUN命令将弹出消息框,显示字符串Child Process。
  • 被调试进程中共发生2此EXCEPTION_ILLEGAL_INSTRUCTION异常,之后程序分别跳转到调试器进程的40121D、401299地址处,继续执行代码,接下来,只要调试这2处代码就能准确把握程序的工作原理。

第六次调试

  1. 发生第一个EXCEPTION_ILLEGAL_INSTRUCTION异常时,将执行40121D地址处的代码。
  2. 重启OllyDbg调试器,在40121D地址处设置断点,再按F9键运行,程序停在40121D,继续跟踪调试401233地址处,遇到调试ReadProcessMemory()代码。
  • 在401233地址处调用ReadProcessMemory() API,从被调试进程401041地址处读取14H字节大小的数据。
  • 触发第一个EXCEPTION_ILLEGAL_INSTRUCTION异常的指令(LEA EAX,EAX)位于40130F地址处,而40141地址正好位于其下(被加密的代码)。
  • 使用StepOver命令执行调用ReadProcMemory() API的指令后,在401240地址处见到XOR解码循环,用7F进行XOR操作。
  • 首先调用ReadProcessMemory() API,将读取的指令代码(处于加密状态)放入缓冲区(0019FCF0~),然后运行解码循环,解密缓冲区中的指令代码,查看缓冲区。
  • 解密后的指令代码像是程序运行命令的一部分,解密后的指令代码中,先引用DebuMe4.exe字符串地址(409A08),然后又在12FD0F地址处又出现了LEA EAX,EAX非法指令,从0019FCF9地址开始,指令代码看上去好像又发生了错乱。
  • 解码循环执行完毕,在调用WriteProcessMemory() API将解码后的指令代码覆写到被调试进程的同一地址空间(401041~401054)。
  • 401266~401295地之间的指令代码用于修改被调试进程的EIP值。
  • 在40127E地址处调用GetThreadContext() API,读取被调试进程的主线的CONTEXT结构体,并将读取到的信息放入其第二个参数pContext指示的缓冲区。
  • 当前被调试线程的EIP地址为40103F,401284地址处的ADD指令将当前EIP值加2,存入pContext->Eip,此时其值为401041,这样就处理了被调试进程40103F地址处发生的EXCEPTION_ILLEGAL_INSTRUCTION异常。
  • 401295地址处调用SetThreadContext() API,向Eip中放入新值,然后跳转到4012C5地址处继续执行。
  • 在4012D4地址处调用ContinueDebugEvent() API,使处于暂停状态的被调试进程再次运行起来,被调试进程运行401041地址处的代码,然后再调用4012F2地址处的WaitForDebugEvent() API,进入等待状态,等待被调试进程发生Debug事件。
  1. 被调试进程发生第一个EXCEPTION_ILLEGAL_INSTRUCTION异常时,就会执行调试进程中的处理代码(40121D)。
  • 普通异常 => 被调试进程
在被调试进程的40103F地址处,由LEA EAX,EAX指令触发EXCEPTION_ILLEGAL_INSTRUCTION异常,此时被调试进程暂停,将控制权转移给调试进程,更准确的说,返回调试进程中调用的WaitForDebugEvent() API。
  • 解码循环(调试器)
调试器从被调试进程读取401041~401054内存区域中的数据,并使用XOR(7F)指令解码,将解码后的实际代码覆写到被调试进程的同一块内存区域。
  • 修改EIP(调试器)
修改被调试进程的代码执行地址(EIP:40103F -> 401041)
  • 调试器处理完40103F地址处的发生的异常后,会使被调试进程再次运行起来,然后进入待机模式,继续等待来自被调试进程的异常。
  1. 401299(第二个异常)
  • 发生第二个EXCEPTION_ILLEGAL_INSTRUCTION异常时,程序将执行401299地址处的代码。
  • 首先在401299地址处设置断点,在上图调用WaitForDebugEvent() API的代码处按F9继续运行,程序就会在401299地址处暂停。
  • 从401299地址开始继续跟踪调试,在4012BC地址处见到调用WriteProcessMemory() API的代码,401299地址处的EAX寄存器表示被调试进程中发生异常的地址->401048.
  • 当前被调试进程的401048地址处的指令为LEA EAX,EAX,被调试进程执行该非法指令时会再次触发异常,4012BC地址处调用WriteProcessMemory() API,将被调试进程的401048地址处的2个字节(8DC0,LEA EAX,EAX)修改为681C(PUSH XXXX指令)。
  • 接下来,在OllyDbg中使用F8执行完调用WriteProcessMemory() API的指令,程序跳转到4012C5地址处,然后调用ContinueDebugEvent()继续运行被调试进程,在调用WaitForDebugEvent()进入待机模式,等待被调试进程发送异常。
  • 最后被调试进程正常运行,弹出消息框。
  1. 归纳
  • 普通异常(被调试者)
在被调试进程的401048地址处由LEA EAX,EAX指令触发EXCEPTION_ILLEGAL_INSTRUCTION异常。
  • 代码补丁(调试器)
调用WriteProcessMemory()API,将681C覆写到被调试进程401048~401049内存区域,681C是PUSH指令的一部分。
  • 继续运行被调试进程(调试器)
处理完异常后,调试器会再次运行被调试进程,然后进入待机状态,等待被调试进程发生异常。

第七次调试

  • 子进程已经处被父进程调试的状态时,该如何调试子进程。
  1. 静态方法
  • 首先详细分析调试进程,得到解码代码,然后直接修改程序的PE文件或进程内存,从而达到OllyDbg调试器调试的目的。
  • 借助第二次调试中使用的方法,将程序调试运行到40103F地址处。
  • 将40103F地址处的LEA EAX,EAX指令修改为NOP,以防该处发生异常。
  • 借助OllyDbg调试器的编辑功能,修改401041~401054地址区域中的指令代码。
  • 修改后的代码
  • 修改代码后即可顺利调试程序,要修改的代码非常简单时,使用以上方法非常方便,但是要修改代码比较长,有比较复杂时,且分布在程序各处时,上述方法使用起来就不怎么方便。
  1. 动态方法
  • 使用动态方法的大致顺序如下:
(1) 使用OllyDbg调试父进程,调试运行到要分析的地方。
(2) 在子进程中要分析的代码处设置无限循环。
(3) 将父进程从子进程中分离。
(4) 附加OllyDbg调试器到子进程。
  • 首先要选择从子进程(被调试进程)的哪一部分开始调试,尽量选择EP处。
  • 子进程中的加密代码解码后,从代码的起始地址(401041)开始调试会比较好,为此,需要先将程序调试运行到父进程相应的代码部分。
  • 首先按Ctrl+F2快捷键重启OllyDbg调试器,在401233地址处设置断点,然后按F9键运行程序。
  • ReadProcessMemory() 的hProcess参数值,后面的调试会在再次用到,解下来的代码对子进程的加密代码解密。
  • 继续调试运行至4012D4地址处,见到调用ContinueDebugEvent()API的代码。
  • 此时,子进程中的大部分加密代码已经被解密,EIP中的地址值也被修改为401041.
  • 注意ContinueDebugEvent() API的2个参数值,ThreadId = 000014CC,ProcessId = 00001D24
  • 调用ContinueDebugEvent() API后,子进程就会再次运行,这样就无法将其附加到OllyDbg调试器,需要现在子进程的代码运行地址处设置无限循环。
  • 子进程被父进程调试,而父进程又正在被OllyDbg调试器调试。
  • 可以先借助OllyDbg向DebugMe4(父进程)进程编写代码,修改DebugMe4进程(子进程)代码,然后再运行。
  • 借助OllyDbg的编辑功能,向4012D2地址处写入2个字节的无限循环代码。
  • 借助汇编功能向4012D4~4012E7地址区域写入汇编代码。
  • 借助OllyDbg的汇编功能对父进程进行了简单的汇编编程,编写的汇编代码调用WriteProcessMemory() API,将无限循环代码设置到子进程。
  • 使用F8指令,从当前EIP地址处开始调试运行到4012E7地址处,即在子进程设置好了无限循环。
  • 设置好无限循环后,接下来就要运行子进程。
  • 再004012EC~004013FB地址区域输入汇编代码,跟踪运行到004012FB地址处,处于暂停状态的子进程就会再次运行起来。
  • DebugActiveProcessStop() API,借助该API可以将被调试者从调试器中分离出来,DebugActiveProcessStop()函数原型如下:
BOOL WINAPI DebugActiveProcessStop(__in DWORD dwProcessId
);

  • 在00401300~00401305地之间编写汇编代码,继续调试运行到00401305地址处,执行CALL DebugActiveProcessStop指令,这样子进程就从父进程中分离出来,此时父进程-子进程关系就断开了,二者称为彼此独立的进程。
  • 附加到DebugMe4.exe进程(子进程),调试在ntdll.DbgBreakPoint()中暂停,由于他是个系统断点,按F9键跳过继续运行,
  • 当前DebugMe4.exe进程就陷入了401041地址处的无限循环,按F12键暂停后,OllyDbg就在当前运行的代码处暂停。
  • 将401041地址处的指令代码恢复为原代码(6A00),将401048地址处的错误指令修改为原指令(681C)。

Debug Blocker相关推荐

  1. 《逆向工程核心原理》

    <逆向工程核心原理> 基本信息 作者: (韩)李承远    译者: 武传海 丛书名: 图灵程序设计丛书 出版社:人民邮电出版社 ISBN:9787115350183 上架时间:2014-4 ...

  2. Apollo:源码分析之cyber\blocker\blocker.h

    BlockerAttr cyber\blocker\blocker_test.cc的第一个使用例子: 首先,BlockAttr说明了Block的一些属性,是用来帮助创建Blocker的.我们来看下它的 ...

  3. pycharm debug后会出现 step over /step into/step into my code /force step into /step out 分别表示...

    1.debug,全部打印 2.打断点debug,出现单步调试等按钮,只运行断点前 3.setup over 调试一行代码 4.setup out 运行断点后面所有代码 5.debug窗口显示调试按钮 ...

  4. Debug常用指令和DOSBox使用步骤

    Debug是Dos系统中著名的调试程序,也可以运行在Windows系统实模下. 优点: 使用Debug程序,可以查看CPU各种寄存器的内容,内存的情况,并且在机器指令级跟踪程序的运行. DosBox: ...

  5. Java IDEA Debug进制二维数组

    1.Debug模式 1.1 什么是Debug模式 是供程序员使用的程序调试工具,它可以用于查看程序的执行流程,也可以用于追踪程序执行过程来调试程序. 1.2 Debug介绍与操作流程 如何加断点 选择 ...

  6. [Advance] How to debug a program (上)

    Tool GDB Examining Memory (data or in machine instructions) You can use the command x (for "exa ...

  7. Keil中使用宏编译来定义DEBUG输出

    使用宏编译来格式化调试信息,是一个不错的方法,即可以在需要的时候打印出信息,还可以格式化我们所需要的输出. #define DEBUG 1 #if (DEBUG == 1) #define DBG(A ...

  8. linux 内核调试信息在哪里,Linux kernel debug技巧----开启DEBUG选项

    Linux kernel debug技巧----开启DEBUG选项 作者:wowo 发布于:2016-11-1 19:39 分类:Linux应用技巧 kernel的source code中有很多使用p ...

  9. debug:g2o cmake时报错“Qt5 not found. Install it and set Qt5_DIR accordingly

    ** debug:g2o cmake时报错"Qt5 not found. Install it and set Qt5_DIR accordingly" ** 完整报错: @ubu ...

最新文章

  1. 一次 MySQL 千万级大表的优化过程
  2. linux下grub故障(使用光盘进入救援模式)
  3. Knockoutjs 实践入门 (2) 绑定事件
  4. CF-825 G.Tree Queries(DFS)
  5. mxGraph实现按住ctrl键盘拖动图形实现复制图形功能
  6. java、sqlserver复习
  7. python selenium 处理弹窗_转:python selenium 弹出框处理的实现
  8. 腾讯Q2财报看点:游戏营收同比止跌 B端业务成第二大营收来源
  9. 基本概念1 IC设计流程
  10. 8.17 记忆增强图神经网络
  11. python+php+变量传递,将变量从php传递给python,将python传递给php
  12. Python3 CookBook | 数据结构和算法(一)
  13. 计算机硬盘大小一般都是整数,电脑硬盘怎么精准整数分区
  14. 数学建模计算机部分知识,数学建模计算机知识的应用
  15. RabbitMQ之业务场景:动态创建,删除队列工具类(一)
  16. calloc和realloc
  17. 计算房租收入比(1)- scrapy 爬取网上租房信息
  18. jellyfin自定义css主题
  19. Java面向对象知识点总结(全)
  20. 每日英语:Report: Chinese Consumers Increasingly Divided

热门文章

  1. 启用和禁用excel 中的加载项
  2. 个人项目总结(论坛系统)
  3. 图像内容修改—修改表格数字及文字
  4. 基于circom、snarkjs实现零知识证明不透漏具体地理位置的区域监控
  5. 用Django编写邮箱注册以及验证码
  6. EasyExcel 读取excel表 解决Empty row EasyExcel末尾出现非常多空白行跳过 EasyExcel跳过末尾空白行
  7. 程序设计天梯赛——T1(15分)java版
  8. 锐捷服务器显示dns无法上网,上网常见故障排查指引-肇庆学院信息中心 Zhaoqing University Information Center...
  9. Java白盒测试三角形函数_白盒测试实验报告-三角形形状-山东大学
  10. 更改计算机的主题和桌面背景,禁止更改电脑主题背景的技巧