反调试/反汇编技术、TEB/PEB部分说明

反调试技术
WindowsAPI
ISDebuggerPresent
查询PEB进程环境块中的ISDebugged标志
CheckRemoteDebuggerPresent
类似于IsDebuggerPresent函数,但是也可以检查其他进程
NtQueryInfomationProcess
提取一个给定进程的信息,第一个参数是进程句柄,第二个参数告诉我们它需要提取的进程信息类型,参数设置为ProcessDebugPort将会告诉你这个句柄标识的进程是否被调试
手动检查数据结构
(1)检查BeingDebugger属性
Windows操作系统维护每一个正在运行的进程的PEB结构,它包含了这个进程相关的所有用户态参数,这些参数包括了进程环境数据,环境数据包括了环境变量,加载模块列表,内存地址,以及调试器状态。
Fs:[30]指向PEB基地址
检查例子:
Mov eax,dowrd ptr fs:[0x30]
Mov ebx,byte ptr[eax+0x2]
Test ebx,ebx
Jz NoDebuggerDetected
(2)检测NTGlobaFlag
PEB结构偏移量0x68有一个位置,来决定如何创建堆结构,如果这个位置的值为0x70那么调试进程的调试器正在运行
例子:
Mov eax,large fs:30h
Cmp dword ptr ds:[eax+0x68],0x70
Jz DebuggerDetected
(3)INT扫描
调试器设置断点的基本方式是软件中断指令INT3,临时替换运行程序中的一条指令,然后当运行到这条指令时,INT3指令时0xCC如果有0xCC存在可能被调试
除了INT3断点外还有INT immediate指令可以设置任意中断该指令有两个操作码0XCD Value
例子:
Call $+5
Pop edi
Sub edi,0x5
Mov ecx,0x400
Mov eax,0xCC
Repne scasb
Jz DebuggerDetcted
(4)时钟检测
被调试是程序运行速度大大降低,所以可以使用时钟检测来探测调试器
使用rdstc指令
较常用的时钟检测是rdstc指令(操作码0x0F31)它返回系统重新启动以来的时钟数,并将一个64位的值的放入EDX,EAX寄存器中,两次运行rdstc指令,然后比较两次的差值。
例子:
Rdtsc
Xor ecx,ecx
Add ecx,ecx
Rdtsc
Sub eax,ecx
Cmp eax,0xFFF
Jb NoDebuggerDetected
Rdtsc
Push eax
ret
时钟检测API:QueryPerformanceCounter和GetTickCount也是实现rdtsc类似功能
混淆技术
线性反汇编(OD/XDBG)、面向代码流反汇编(IDApro)
(1)相同目标跳转指令混淆:
恶意代码中最常见的对抗反汇编技术,指向同一目标的地址的两个连续跳转指令,效果等于无条件跳转的JMP指令,因为反汇编器每次只反汇编一条指令,所以并不会意识到这种情况,依然会反汇编这个指令的false分支,尽管事实上这个分支永远不会执行。
混淆情况例子:
0x74 0x03 Jz short near ptr 0x4011C4+1
0x75 0x01 Jnz short near ptr 0x4011C4+1
0xE8 0X58 0XC3 0X90 0X90 Call near ptr 0x90D0521H
真实指令:跳转到POP混淆以为是CALL指令
JZ |JNZ |E8 POP RET
0x74/0x73|0x75/0x01 |CALL 0x58 0xC3
(2)固定条件的跳转指令
另一种常见的对抗反汇编技术是由跳转条件总是相同的一条跳转指令构成。
混淆情况例子:
0x33 0xc0Xor eax,eax
0x74 0x01 Jz short near ptr loc_4011C4+1
Loc_4011C4:
0xE9 0X58 0XC3 0X68 0X94 jmp near ptr 94A8D521h
真实指令:jmp指令为混淆指令,类似于上述call指令并非真正的实际指令
0x33 0xc0 xor eax,eax
0x74 0x01 jz short near ptr loc_4011C5
E9 混淆db 0E9h
0x58 pop eax
0xC3 retn
注释:jz跳过E9字节
XOR |jz |E9 |POP|RET
0x33 0XC0 |0x74 0x01 |JMP|0x58|0xC3
(3)无效的反汇编指令
上述1和2都是流氓字节他们不属于程序的一部分,主要是用来迷惑反汇编者的,但是如果流氓字节时指令流程的一部分那么将很难正确识别
例子:
反调试/反汇编技术、TEB/PEB部分说明_第1张图片

可以看到最后jmp 5之后没有执行0xE8为开头的CALL指令而是执行其他指令,通过JZ-6
之中执行真实指令,上述mov、xor、call、均为混淆指令但是与流氓字节不同本身又是正常指令逻辑的一部分。
TEB(线程环境块)
TEB线程环境块,结构中包含了系统频繁操作的使用的一些与线程相关的数据,进程中每个线程(系统线程除外)都有一个自己的TEB,一个进程的所有TEB都存放在0x7FFDE000开始的线性内存中,每4KB为一个完整的TEB
TEB结构:
000 指向SEH链指针
SEH链:
004 线程堆栈顶部
008 线程堆栈底部
00C SubSystemTib
010 FiberData
014 ArbitraryUserPointer
018 FS段寄存器在内存中的镜像地址
020 进程PID
024 线程ID
02C 指向线程局部存储指针
030 PEB结构地址(进程结构)
034 上个错误号
PEB(进程环境块)

PEB结构:(PEB是进程环境块位于TEB偏移0x30处)
PEB进程环境块存在于用户地址空间中,记录了进程的相关信息,每个进程都有自己的PEB信息
PEB结构信息:
0x2 标志当前进程是否被调试
0x8 进程的映像基址地址
0xC 有PE Loader填充,包含很多pe中的信息,用来枚举用户加载的模块
0x10 指向 RTL_USER_PROCESS_PARAMETERS的指针
0x14 指向进程堆首地址,每个进程新建是默认使用

你可能感兴趣的:(汇编,c++)