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. 百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库OD反调试大全(6)在线全文阅读。
相关推荐: