结合复习PPT简单谈谈一些东西的理解
对于汇编的代码还没有完全整理(还可以更多),其他的简单写了一些更细致的东西
IDA代码
olldbg和汇编指令
下面这个就是复习一下之前的实验:
多半是问答的东西
SEH结构体异常
SEH(Structured Exception Handling)是Windows中的一种结构化异常处理机制。它使得Windows程序可以利用__try, __except, __finally等关键字方便地处理异常。一个简单的SEH示例代码如下:
c __try { // 可能发生异常的代码块 int *p = NULL; *p = 1; // 跑出访问空指针异常 } __except(EXCEPTION_EXECUTE_HANDLER) { // 异常处理代码块 printf("Oops, exception occurred!\n"); } __finally { // 无论是否发生异常,此代码块都会执行 printf("This is finally block\n"); }- __try {...}: 可能发生异常的代码块
- __except {...}: 用于捕获和处理__try中的异常
- __finally {...}: 不管__try中是否发生异常,__finally中的代码都会执行,一般用于资源清理。当在__try块中发生异常时,系统会在__except块中寻找匹配的异常处理程序进行异常处理。如果没有找到匹配的处理程序,异常会沿调用栈向上传播。SEH对于结构化地处理Windows程序中的异常非常有用,是Windows异常处理体系的重要组成部分。
花指令
花指令是一种CPU指令,用于混淆和隐藏实际的指令流程,以防止逆向工程和代码破解。它通过插入无效或无意义的指令来误导反汇编和逆向分析工具。常见的花指令技术有: - 僵尸代码:插入无意义的代码,不影响主程序逻辑。 - 代码重排:改变指令顺序,使逻辑难以理解,但最终结果不变。 - 变量替换:使用中间变量来隐藏真实操作数。 - 假条件跳转:在条件跳转指令中使用恒真或恒假的条件,来隐藏实际控制流。 - 指令替换:用等价但更难分析的指令替换简单指令。 举个简单的例子: 没有花指令:assembly mov eax, 1 add eax, 2加入花指令后:
assembly mov ebx, 0 ; 僵尸代码 mov ecx, 5 ; 僵尸代码 add eax, 2 ; 指令重排 mov eax, 1可以看到,通过插入无意义指令和改变指令顺序,使代码的实际逻辑变得难以理解,这是一种简单的代码混淆技术。花指令技术在保护软件代码和防止恶意逆向方面有一定的应用。但随着破解技术的提高,花指令的有效性也在下降。更高级的保护手段是通过算法和数据结构来隐藏程序逻辑,而不仅仅依靠指令层面的混淆。
这里的ebx和ecx是纯粹没有用的东西
找OEP
oep,(程序入口点)寻找方式:ESP定律。
堆栈平衡定律即程序运行时入栈的量一定等于出栈的量,当我们加壳时,回导致程序的入口发生变化,壳程序会另外使用栈帧去运行源程序,并且壳程序一旦将源程序运行之后,自己便不会运行,也就是说是这样的流程:
壳程序入栈,壳程序出栈,源程序入栈,源程序出栈
因此,我们可以对壳程序的入口进行监测,记录入栈数,然后分析什么时候出栈数与壳入口的入栈相等,那么下一步就是源程序的入口
脱壳和stolen code
将一部分源程序需要的代码放进壳里防止有人找到oep的位置后直接脱壳,是一种防脱壳的手段
下面是反调试
反调试技术
Windows API提供了一些函数来检测调试器的存在与否。主要有以下几种方法:
1. IsDebuggerPresent()函数:直接检查是否有调试器运行。此方法简单可靠,但容易被 patching。
2. CheckRemoteDebuggerPresent()函数:检查其他进程是否正在调试当前进程。此方法有一定的迷惑性,但也可被 patching。
3. NtQueryInformationProcess()函数:该函数可获取进程的各种信息,其中PROCESSINFOCLASS::ProcessDebugPort和ProcessDebugFlags可以判断进程是否被调试。使用这种方法较难发现,但需要对系统底层有比较深入的理解,也可被一定的修复。
在理解反调试技术上时,我们不要让我们作为一个攻击方去理解,而是作为一个防守方去理解,首先假设你是一个程序拥有者,你为了防止自己的程序被人调试要进行什么操作呢?
同时,再假设你是一个程序使用者,你使用的程序有可能被人增加了木马等,为了防止出现问题检查程序是否被人动过
那么windows API就是直接在程序内部调用函数去反调试,检测到后就不运行程序等,是作为程序拥有者进行的,
手动检查就是程序使用者的选择了
系统痕迹检测(System Footprint Detection)是软件保护中常用的一种技术。它通过检测系统中某些特征信息来判断软件的运行环境,并采取相应的保护措施。
他既可以被拥有者使用,也可以被使用者使用,我们下面的知识点多是指代被使用者使用
checkdebug()函数是软件保护中常用的一种反调试技术。它通过设置一个断点,然后判断该断点是否会触发来判断调试器的存在。
基本实现步骤如下:
1. 选择一个地址addr作为断点设置位置。这个地址应该在正常运行中不会执行到,一般选择某个未使用的函数中。
2. 在地址addr处设置一个软件断点或硬件断点。3. 执行一段代码come_code,该代码会引起断点addr被触发。比如调用addr所在的函数。
4. 校验断点是否被触发。如果触发,表明存在调试器,否则调试器不存在。
5. 清除设置的断点,以免影响程序正常运行。
判断断点是否触发的方法主要有:
1. 读取调试器的断点命中次数信息,判断addr对应的断点是否有增加。这需要知道调试器的断点表在哪,以及如何读取断点信息。
2. 在come_code执行结束后读取addr处的指令,判断是否已经由INT 3替换。如果是,表明断点被触发。这需要知道INT 3指令在不同环境下的具体编码。
3. 使用时间检测方法对come_code段进行检测。如果时间受到addr断点的影响而改变,则断点被触发。这需要非常精确的时间检测方法。
4. 在断点处理函数中添加处理代码。当addr断点触发时将执行我们的处理代码,从而判定断点被触发。这需要知道不同调试器的断点处理函数及机制。
5. 反汇编come_code得到对应的汇编指令,判断这些指令在运行后是否已执行。如果addr处的指令未执行,表明断点被触发。这需要熟练的反汇编技能。
所以,checkdebug()函数需要比较深入地理解不同调试器的工作机制和断点实现方法,才能设计有效的判断断点触发的手段。同时也要熟练运用各种反汇编与调试技术来还原程序的运行过程。这是一种比较高级的反调试技术,需要不断实践和总结调试器的新功能来更新判断方法,以避免被轻易绕过。这也带来一个 "对抗" 的过程,需要调试器开发者不断改进来提高软件的防护能力。
1. TLS回调: 是线程局部存储(Thread Local Storage)的缩写。每个线程都有自己的TLS存储区域,可以在线程内部访问。利用TLS回调机制,我们可以在线程切换的时候执行自定义的代码。这样我们就可以在线程切换时探测调试器,如果发现调试器,就采取相应措施。
2. 中断: 我们可以在程序运行时主动触发CPU的软件中断或硬件中断,在中断处理函数中检测调试器的存在。如果调试器在监视该程序,它也会在我们的中断处理函数被调用时进行上下文切换,这就可以被我们的代码检测出来。
3. 陷阱标志位: 我们可以设置CPU的陷阱标志位,然后故意让程序执行一条会触发陷阱的指令。在陷阱处理函数中 similarly 可以检测调试器。
便于理解一些,我们说一下底层的东西,实际上程序如果依托调试器只是在模拟一个cpu运行而非真的直接在cpu里运行,程序的机器码都不会真的在cpu里跑,而是在调试器里。
反调试技术之所以行之有效,是因为在调试过程中,程序的执行实际上是由调试器控制和管理的,而不是直接由CPU执行的。具体来说:1. 当程序在调试器中运行时,调试器会在线程切换时暂停程序的执行,以进行上下文切换。这就可以被TLS回调机制探测到。2. 软件或硬件中断也同样会使得调试器暂停程序的执行,这段时间里程序所占用的CPU时间会减少或消失,这可以被我们的检测代码捕获到。3. 同样的,当我们设置陷阱标志位触发陷阱时,调试器也会得以响应,暂停程序的执行,这也可以被我们检测到。所以,简而言之,这些技术之所以行得通,是因为在调试环境下,程序的执行控制权实际上在调试器手中,而非CPU。调试器为了实现调试的功能,必然会在某些时刻改变程序正常的执行流程,这些改变可以被我们检测并利用来抵御调试器的分析。
标签:__,逆向,复习,代码,程序,指令,整理,断点,调试器 From: https://www.cnblogs.com/nish1hundun/p/17489869.html