Trao đổi với tôi

http://www.buidao.com

12/9/10

[Reverse] Anti Reverse (Anti BreakPoint)


Bài viết tham khảo từ http://www.codeproject.com/KB/securi...gineering.aspx

Nói về breakpoint thì chắc hẳn những ai đã làm việc trên các trình debug đều biết đến. Break point có 3 loại đó là : hardware, memory, and INT 3h breakpoints. Break point cho phép chúng ta dừng thực thi chương trình tại nơi ta đã thiết lập, điều này giúp ích cho chúng ta trong việc khảo sát hoạt động của các hàm.(ví dụ set một bp trên hàm API VirtualAlloc(cấp phát bộ nhớ) biết thuộc tính,kích thước của vùng nhớ sẽ cấp phát,v,v thông qua các đối số đẩy lên stack, và địa chỉ vùng nhớ đã được cấp phát sau thi thực thi xong hàm lưu trong eax).Và để gây khó khăn trong qua trình dịch ngược(RE) một số phương pháp anti bp đã được tạo ra và nó đã được sử dụng trong các packer,virus.

Trong vài viết tui sẽ minh hoạ bằng 0llydbg các bạn có thể tải trình debug này tại http://ollydbg.de/

INT 3 BreakPoint

Int 3h breakpoint được miêu tả trong tập chỉ thị IA-32 với opcode là CC. Trong OllyDbg khi ta set một int 3 bp(F2) tại một địa chỉ bất kì giả sử là 401000 trình debug sẽ save 1 byte opcode tại 401000 và write một opcode mã hex 0xCC tại 401000 khi chương trình thực thi đến chỉ thị tại 401000 sẽ sinh ra một excetion gửi đến trình debug. Và trong hàm lọc exception của debug sẽ xử lý exception đó,Tôi sẽ không di sâu thêm về phần này các bạn có thể tham khảo cách tạo ra một chương trình debug đơn giản qua 3 tut iczelion.

Tut 28:http://win32assembly.online.fr/tut28.html
Tut 29:http://win32assembly.online.fr/tut29.html
Tut 30:http://win32assembly.online.fr/tut30.html

Nên nói một đơn giản để detect một Int 3 Bp ta sẽ search opcode 0xCC tại vùng nhớ cần anti BP.

bool CheckForCCBreakpoint(void* pMemory, size_t SizeToCheck)
{
unsigned char *pTmp = (unsigned char*)pMemory;
for (size_t i = 0; i < SizeToCheck; i++)
{
if(pTmp[i] == 0xCC)
return true;
}

return false;
}

pMemory trỏ đến địa chỉ bắt đầu tìm kiếm , SizeToCheck kich thước vùng nhớ cần tìm kiếm.Nhưng để tránh phát hiện đoạn mã kiếm tra int 3 bp ta sẽ ma hoá opode 0xCC bằng phép xor.Trpng ví dụ trên sau khi biên dịch

if(pTmp[i] == 0xCC) giả sử sau khi biện dịch sẽ tương đương

cmp edx,0xCC ;sẽ bị phát hiện tại đây
jnz ...

nhưng khi kiểm tra opcode 0xCC đã mã hoá với phép xor:
if( 0x99 == (tmpchar ^ 0x55) )

and edx,0ff ;lấy một byte opcode đang xét
xor edx,55 ;dem xor với 55
cmp edx,0x99 ;nếu bằng 99 là int 3bp (nếu opcode đang xét là 0xCC xor 55 sẽ bằng 0x99)
jnz ...

Phương pháp này được dùng trong packer như Armadillo.


Code minh hoạ:
Code :
/*
DEMO ANTI INT3 BREAK POINT
Reference Source code from: [URL="http://www.codeproject.com/"]http://www.codeproject.com[/URL]
Author: quangthiennguyen
Mail: [email]mrquangthien@gmail.com[/email]
*/
#include

bool CheckForCCBreakpointXor55(void* pMemory, size_t SizeToCheck)
{
unsigned char *pTmp = (unsigned char*)pMemory;
unsigned char tmpchar = 0;

for (size_t i = 0; i < SizeToCheck; i++)
{
tmpchar = pTmp[i];
if( 0x99 == (tmpchar ^ 0x55) ) // 0xCC xor 0x55 = 0x99
return true;
}

return false;
}

void Myfunction(void)
{
goto body;
__asm{
_emit 'P'
_emit 'L'
_emit 'E'
_emit 'A'
_emit 'S'
_emit 'E'
_emit ' '
_emit 'S'
_emit 'E'
_emit 'T'
_emit '.'
_emit 'I'
_emit 'N'
_emit 'T'
_emit '3'
_emit '.'
_emit 'B'
_emit 'P'
_emit '.'
_emit 'H'
_emit 'E'
_emit 'R'
_emit 'E'
_emit '.'
_emit '!'
}
body:
int a=1;
int b=2;
int c=a+b;
a=c^b;
c=b&a;
}
void Myfunction_END(void) { };


int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )
{


size_t nSizeScan=(size_t)(Myfunction_END) - (size_t)(Myfunction);

if (CheckForCCBreakpointXor55(&Myfunction,nSizeScan))
{
MessageBoxA(0,"Found Int3 BP at Myfunction","Detect",0);
return 1;
}
Myfunction();//ham kiem tra bp
MessageBoxA(0,"Not found Int3 BP at Myfunction","Detect",0);

return 0;
}
Bây giờ build code trên và load file exe lên olly chúng ta sẽ tìm thấy đoạn hàm kiểm tra int3 bp qua chuỗi opcode hiển được hiển thị chuỗi ASCII trong olly “PLEASE.SET.INT3.BP.HERE” tui thêm vào để cho các bạn dễ tìm kiếm,sau đó xét một int3 tại một chỉ thị bất kì (F2) như trong hình nó là 401237.



Attachment 819


Memory BreakPoint

Memory breakpoint hoạt động dựa trên thuộc tính bảo vệ của vùng nhớ và các exception sinh ra khi truy cập trái phép với thuộc tính bảo vệ của vùng nhớ đó.

Bạn có thể tham khảo hàm VirtualProtect tại:
http://msdn.microsoft.com/en-us/libr...=VS.85%29.aspx

Ví dụ khi bạn truy cập một vùng nhớ được đánh dấu thuộc tính bảo vệ là PAGE_GUARD sẽ phát sinh ra một exception STATUS_GUARD_PAGE_VIOLATION và khi bạn đang chạy trong một trình debug nó sẽ đựợc trong hàm lọc exception của debug và trình debug sẽ xem nó là một memory breakpoint (ollydbg) break tại page đã xét memory bp.Chúng ta sẽ dựa vào đặc điếm này dể detect một debuger đang chạy (các bạn lưu ý là chúng ta chỉ detect debuger không phải là detect memory bp).



Code minh hoạ:
Code :

/*
DEMO DETECT DEBUGGER BY MEMORY BREAK POINT METHOD
Reference Source code from: http://www.codeproject.com
Author: quangthiennguyen
Mail: mrquangthien@gmail.com
*/

#include

bool MemoryBreakpointDebuggerCheck()
{
unsigned char *pMem = NULL;
SYSTEM_INFO sysinfo = {0};
DWORD OldProtect = 0;
void *pAllocation = NULL; // Get the page size for the system

GetSystemInfo(&sysinfo); // Allocate memory

pAllocation = VirtualAlloc(NULL, sysinfo.dwPageSize,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE);

if (pAllocation == NULL)
return false;

// Write a ret to the buffer (opcode 0xc3)
pMem = (unsigned char*)pAllocation;
*pMem = 0xc3;

// Make the page a guard page
if (VirtualProtect(pAllocation, sysinfo.dwPageSize,
PAGE_EXECUTE_READWRITE | PAGE_GUARD,
&OldProtect) == 0)
{
return false;
}

__try
{
__asm
{
mov eax, pAllocation
// This is the address we'll return to if we're under a debugger
// push &MemBpBeingDebugged
push ecx
lea ecx,MemBpBeingDebugged
push ecx
jmp eax // Exception or execution, which shall it be :D?
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
// The exception occured and no debugger was detected
__asm{pop ecx}
VirtualFree(pAllocation, NULL, MEM_RELEASE);
return false;
}

__asm{MemBpBeingDebugged:}
__asm{pop ecx}
VirtualFree(pAllocation, NULL, MEM_RELEASE);
return true;
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )
{
if (MemoryBreakpointDebuggerCheck())
{
MessageBoxA(0,Found Debugger!,"Detect",0);
return 1;
}
MessageBoxA(0,"Found Debugger!","Detect",0);
return 0;
}

Giải thích code:
-Đầu tiên chúng ta sẽ cấp phát một vùng nhớ bằng API VirtualAlloc thuộc tính PAGE_EXECUTE_READWRITE vùng nhớ được phép thực thi, đọc và ghi trên nó.
-Sau đó patch lệnh RET(0xC3) lên vùng nhớ vừa cấp phát

-Sau đó đánh dấu thuộc tính vùng nhớ thành page guard bằng API VirtualProtect
-Tạo một handling exceptions __try{ }__except { }
1.Khi thực run file exe bình thường sẽ phát sinh except và sẽ xử lý tiếp trong lock __except (giải phóng vùng nhớ đã cấp phát và return false)
2.Khi run trong trình debug sẽ xem nó như một MemoryBP và break tại vùng nhớ đã cấp phát
Attachment 820

Sau khi run tiếp chúng ta se nhảy đến nhãn __asm{MemBpBeingDebugged:}rồi giải phóng vùng nhớ đã cấp phát sau đó return true(debugger detect) tại sao chúng ta lại nhảy đến MemBpBeingDebugged: vì trước đó ta đã lấy address của nhãn MemBpBeingDebugged: lưu vào ebx
lea ecx,MemBpBeingDebugged
Sau đó push lên stack
push ecx

Sau đó nhảy đến page guard
jmp eax

Tại page guard sẽ thực thi tiếp chỉ thị
ret

vì trước đó stack đã lưu address nhãn MemBpBeingDebugged nên ret sẽ lấy địa chỉ trở lại trên stack và thanh ghi IP sẽ được trỏ đến nhãn address nhãn MemBpBeingDebugged và thực thi tiếp.

Hardware Breakpoints

Phương pháp này chủ dựa vào các thanh ghi debug
Tui sẽ không đi sâu vào phần này các bạn có thể tham khảo thêm tut của benia http://virusvn.com/forum/showthread....ooking-Part-1-



Code tham khảo:
Code :
/*
DEMO ANTI HARDWARE BREAKPOINT
Reference Source code from: http://www.codeproject.com
Author: quangthiennguyen
Mail: mrquangthien@gmail.com
*/

#include
#include

int CheckHardwareBreakpoints()
{
unsigned int NumBps = 0;
// This structure is key to the function and is the
// medium for detection and removal
CONTEXT ctx;
ZeroMemory(&ctx, sizeof(CONTEXT));

// The CONTEXT structure is an in/out parameter therefore we have
// to set the flags so Get/SetThreadContext knows what to set or get.
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;

// Get a handle to our thread
HANDLE hThread = GetCurrentThread();

// Get the registers
if(GetThreadContext(hThread, &ctx) == 0)
return -1;

// Now we can check for hardware breakpoints, its not
// necessary to check Dr6 and Dr7, however feel free to
if(ctx.Dr0 != 0)
++NumBps;
if(ctx.Dr1 != 0)
++NumBps;
if(ctx.Dr2 != 0)
++NumBps;
if(ctx.Dr3 != 0)
++NumBps;

return NumBps;
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )
{

unsigned int nHWBP=0;
char szmsg[100]={0};

nHWBP=CheckHardwareBreakpoints();
if (nHWBP)
{
sprintf(szmsg,"Found %d HWBP",nHWBP);
MessageBoxA(0,szmsg,"Detect",0);
return 1;
}
MessageBoxA(0,"Not found HWBP","Detect",0);

return 0;
}