OD反调试大全(6)

2019-02-16 00:42

mov dword ptr [ecx+0A4h], -1 // EBX = -1 -> not running, ebx = 0 -> running add dword ptr [ecx+0B8h], 4 // -> skip past the call to VPC xor eax, eax // exception is handled ret ret1: ret } }

3.12 FV_VME_RedPill

这个方法似乎是检测虚拟机的一个简单有效的方法,虽然还不能确定它是否是100%有效。名字很有意思,红色药丸(为什么不是bluepill,哈哈)。我在网上找到了个ppt专门介绍这个方法,可惜现在翻不到了。记忆中原理是这样的,主要检测IDT的数值,如果这个数值超过了某个数值,我们就可以认为应用程序处于虚拟环境中,似乎这个方法在多CPU的机器中并不可靠。据称ScoobyDoo方法是RedPill的升级版。代码也是在网上找的,做了点小改动。有四种返回结果,可以确认是VMWare,还是VirtualPC,还是其它VME,或是没有处于VME中。

//return value: 0:none,1:vmvare;2:vpc;3:others unsigned char matrix[6];

unsigned char redpill[] =

\

HANDLE hProcess = GetCurrentProcess();

LPVOID lpAddress = NULL;

PDWORD lpflOldProtect = NULL;

__try {

*((unsigned*)&redpill[3]) = (unsigned)matrix;

lpAddress = VirtualAllocEx(hProcess, NULL, 6, MEM_RESERVE|MEM_COMMIT , PAGE_EXECUTE_READWRITE);

if(lpAddress == NULL) return 0;

BOOL success = VirtualProtectEx(hProcess, lpAddress, 6, PAGE_EXECUTE_READWRITE , lpflOldProtect);

if(success != 0) return 0;

memcpy(lpAddress, redpill, 8);

((void(*)())lpAddress)();

if (matrix[5]>0xd0) {

if(matrix[5]==0xff)//vmvare return 1;

else if(matrix[5]==0xe8)//vitualpc return 2; else

return 3; } else return 0; }

__finally {

VirtualFreeEx(hProcess, lpAddress, 0, MEM_RELEASE); }

四、 检测-断点(FB_)

这一部分内容较少,但实际上可用的方法也比较多,我没有深入研究,不敢乱写,照抄了几个常用的方法: //find breakpoint

bool FB_HWBP_Exception(); DWORD FB_SWBP_Memory_CRC();

bool FB_SWBP_ScanCC(BYTE * addr,int len);

bool FB_SWBP_CheckSum_Thread(BYTE *addr_begin,BYTE *addr_end,DWORD sumValue);

4.1 FB_HWBP_Exception

在异常处理程序中检测硬件断点,是比较常用的硬件断点检测方法。在很多地方都有提到。 __asm {

push offset exeception_handler; set exception handler push dword ptr fs:[0h] mov dword ptr fs:[0h],esp

xor eax,eax;reset EAX invoke int3 int 1h

pop dword ptr fs:[0h];restore exception handler add esp,4

;test if EAX was updated (breakpoint identified) test eax,eax jnz rt_label

jmp rf_label

exeception_handler: ;EAX = CONTEXT record

mov eax,dword ptr [esp+0xc]

;check if Debug Registers Context.Dr0-Dr3 is not zero cmp dword ptr [eax+0x04],0 jne hardware_bp_found

cmp dword ptr [eax+0x08],0 jne hardware_bp_found

cmp dword ptr [eax+0x0c],0 jne hardware_bp_found

cmp dword ptr [eax+0x10],0 jne hardware_bp_found jmp exception_ret

hardware_bp_found:

;set Context.EAX to signal breakpoint found mov dword ptr [eax+0xb0],0xFFFFFFFF exception_ret:

;set Context.EIP upon return

inc dword ptr [eax+0xb8];set ContextRecord.EIP inc dword ptr [eax+0xb8];set ContextRecord.EIP xor eax,eax retn }

4.2 FB_SWBP_Memory_CRC()

由于在一些常用调试器中,比如OD,其是将代码设置为0xcc来实现普通断点,因此当一段代码被设置了普通断点,则其中必定有代码的修改。因此对关键代码进行CRC校验则可以实现侦测普通断点。但麻烦的是每次代码修改,或更换编译环境,都要重新设置CRC校验值。 下面的代码拷贝自《软件加解密技术》,里面完成的是对整个代码段的CRC校验,CRC校验值保存在数据段。CRC32算法实现代码网上有很多,就不列出来了。 DWORD FB_SWBP_Memory_CRC() {

//打开文件以获得文件的大小

DWORD fileSize,NumberOfBytesRW; DWORD

CodeSectionRVA,CodeSectionSize,NumberOfRvaAndSizes,DataDirectorySize,ImageBase; BYTE* pMZheader; DWORD pPEheaderRVA; TCHAR *pBuffer ;

TCHAR szFileName[MAX_PATH];

GetModuleFileName(NULL,szFileName,MAX_PATH); //打开文件

HANDLE hFile = CreateFile( szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,

OPEN_EXISTING,

FILE_ATTRIBUTE_NORMAL, NULL);

if ( hFile != INVALID_HANDLE_VALUE ) {

//获得文件长度 :

fileSize = GetFileSize(hFile,NULL); if (fileSize == 0xFFFFFFFF) return 0;

pBuffer = new TCHAR [fileSize]; //// 申请内存,也可用VirtualAlloc等函数申请内存 ReadFile(hFile,pBuffer, fileSize, &NumberOfBytesRW, NULL);//读取文件内容 CloseHandle(hFile); //关闭文件 } else

return 0;

pMZheader=(BYTE*)pBuffer; //此时pMZheader指向文件头

pPEheaderRVA = *(DWORD *)(pMZheader+0x3c);//读3ch处的PE文件头指针

///定位到PE文件头(即字串“PE\\0\\0”处)前4个字节处,并读出储存在这里的CRC-32值:

NumberOfRvaAndSizes=*((DWORD *)(pMZheader+pPEheaderRVA+0x74));//得到数据目录结构数量

DataDirectorySize=NumberOfRvaAndSizes*0x8;//得到数据目录结构大小 ImageBase=*((DWORD *)(pMZheader+pPEheaderRVA+0x34));//得到基地址 //假设第一个区块就是代码区块 CodeSectionRVA=*((DWORD

*)(pMZheader+pPEheaderRVA+0x78+DataDirectorySize+0xc));//得到代码块的RVA值 CodeSectionSize=*((DWORD

*)(pMZheader+pPEheaderRVA+0x78+DataDirectorySize+0x8));///得到代码块的内存大小 delete pBuffer; // 释放内存

return CRC32((BYTE*)(CodeSectionRVA+ImageBase),CodeSectionSize); }

4.3 FB_SWBP_ScanCC

扫描CC的方法,比照前面校验代码CRC数值的方法更直接一些,它直接在所要检测的代码区域内检测是否有代码被更改为0xCC,0xcc对应汇编指令为int3 ,对一些常用的调试器(如OD)其普通断点就是通过修改代码为int3来实现的。但使用时要注意是否正常代码中就包含CC。通常这个方法用于扫描API函数的前几个字节,比如检测常用的MessageBoxA、

GetDlgItemTextA等。

bool FB_SWBP_ScanCC(BYTE * addr,int len) {

FARPROC Func_addr ;

HMODULE hModule = GetModuleHandle(\

(FARPROC&) Func_addr =GetProcAddress ( hModule, \if (addr==NULL)

addr=(BYTE *)Func_addr;//for test BYTE tmpB; int i; __try {

for(i=0;i

tmpB=*addr; tmpB=tmpB^0x55;

if(tmpB==0x99)// cmp 0xcc return true; } }

__except(1) return false; return false; }

4.4 FB_SWBP_CheckSum_Thread(BYTE *addr_begin,BYTE *addr_end,DWORD sumValue); 此方法类似CRC的方法,只是这里是检测累加和。它与CRC的方法有同样的问题,就是要在编译后,计算累加和的数值,再将该值保存到数据区,重新编译。在这里创建了一个单独的线程用来监视代码段。

DWORD WINAPI CheckSum_ThreadFunc( LPVOID lpParam ) {

DWORD dwThrdParam[3]; BYTE tmpB; DWORD Value=0;

dwThrdParam[0]=* ((DWORD *)lpParam); dwThrdParam[1]=* ((DWORD *)lpParam+1); dwThrdParam[2]=* ((DWORD *)lpParam+2); BYTE *addr_begin=(BYTE *)dwThrdParam[0]; BYTE *addr_end=(BYTE *)dwThrdParam[1]; DWORD sumValue=dwThrdParam[2];

for(int i=0;i<(addr_end-addr_begin);i++) Value=Value+*(addr_begin+i);

/* //if sumvalue is const,it should be substract.


OD反调试大全(6).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:2017-2022年中国海上风力发电产业需求分析及发展趋势预测 - 图文

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: