In this side note, we take a closer look at the source code of some bots. We demonstrate several
examples of techniques used by current bots to either speed-up computations or to detect suspicious
environments, such as detection of debuggers or virtual machines such as VMware. Furthermore, some bots
use different techniques to make forensic analysis much more difficult.
1.
Detecting SoftICE//检测SoftIce
/*
Function: IsSICELoaded
Description: This method is used by a lot of crypters/compresors it uses INT 41,
this interrupt is used by Windows debugging interface to detect if a
debugger is present. Only works under Windows.
Returns: true if a debugger is detected
*/
__inline bool IsSICELoaded() {
_asm {
mov ah, 0x43
int 0x68
cmp ax, 0x0F386 // Will be set by all system debuggers.
jz out_
xor ax, ax
mov es, ax
mov bx, word ptr es:[0x68*4]
mov es, word ptr es:[0x68*4+2]
mov eax, 0x0F43FC80
cmp eax, dword ptr es:[ebx]
jnz out_
jmp normal_
normal_:
xor eax, eax
leave
ret
out_:
mov eax, 0x1
leave
ret
}
return false;
}
2.
Detecting SoftICE NT
/*
Function: IsSoftIceNTLoaded
Description: Like the previous one but for use under Win NT only
Returns: true if SoftIce is loaded
*/
__inline BOOL IsSoftIceNTLoaded() {
HANDLE hFile=CreateFile( ".//NTICE",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile!=INVALID_HANDLE_VALUE) { CloseHandle(hFile); return true; }
return false;
}
3.
Detecting OllyDbg//检测OllyDbg
/*
Function: IsODBGLoaded
Description: Tests if OllyDbg/other app debuggers is/are enabled
Returns: true if a debugger is detected
*/
__inline bool IsODBGLoaded() {
char *caption="DAEMON";
_asm {
push 0x00
push caption
mov eax, fs:[30h] // pointer to PEB
movzx eax, byte ptr[eax+0x2]
or al,al
jz normal_
jmp out_
normal_:
xor eax, eax
leave
ret
out_:
mov eax, 0x1
leave
ret
}
}
4.
Detecting Breakpoints//检测端点
/*
Functions are declared as __inline, this causes the expansion of this code each time a function
is invoked, this is to difficult the cracker work by using this function more than once time
Function: IsBPX
Description: Checks if the given memory address is a breakpoint
Returns: true if it is a breakpoint
*/
__inline bool IsBPX(void *address) {
_asm {
mov esi, address // load function address
mov al, [esi] // load the opcode
cmp al, 0xCC // check if the opcode is CCh
je BPXed // yes, there is a breakpoint
// jump to return true
xor eax, eax // false,
jmp NOBPX // no breakpoint
BPXed:
mov eax, 1 // breakpoint found
NOBPX:
}
}
5.
Detecting VMWare//检测虚拟机VMWARE
/*
executes VMware backdoor I/O function call
*/
#define VMWARE_MAGIC 0x564D5868 // Backdoor magic number
#define VMWARE_PORT 0x5658 // Backdoor port number
#define VMCMD_GET_VERSION 0x0a // Get version number
int VMBackDoor(unsigned long *reg_a, unsigned long *reg_b, unsigned long *reg_c, unsigned long *reg_d) {
unsigned long a, b, c, d;
b=reg_b?*reg_b:0;
c=reg_c?*reg_c:0;
xtry {
__asm {
push eax
push ebx
push ecx
push edx
mov eax, VMWARE_MAGIC
mov ebx, b
mov ecx, c
mov edx, VMWARE_PORT
in eax, dx
mov a, eax
mov b, ebx
mov c, ecx
mov d, edx
pop edx
pop ecx
pop ebx
pop eax
}
} xcatch(...) {}
if(reg_a) *reg_a=a; if(reg_b) *reg_b=b; if(reg_c) *reg_c=c; if(reg_d) *reg_d=d;
return a;
}
/*
Check VMware version only
*/
int VMGetVersion() {
unsigned long version, magic, command;
command=VMCMD_GET_VERSION;
VMBackDoor(&version, &magic, &command, NULL);
if(magic==VMWARE_MAGIC) return version;
else return 0; }
/*
Check if running inside VMWare
*/
int IsVMWare() {
int version=VMGetVersion();
if(version) return true; else return false;
}
6.
Fooling ProcDump
/*
Fool ProcDump with increasing size
*/
void FoolProcDump() {
__asm {
mov eax, fs:[0x30]
mov eax, [eax+0xC]
mov eax, [eax+0xC]
add dword ptr [eax+0x20], 0x2000 // increase size variable
}
}
7.
Combining everything
bool CDebugDetect::IsDebug() {
#ifdef _DEBUG
return false;
#else
if(m_bIsDebug) return true;
#ifndef _WIN32
// Anti-PTrace
// if(ptrace(PTRACE_TRACEME, 0, 1, 0)<0) {
// m_bIsDebug=true; return true;
// }
#else
pfnIsDebuggerPresent IsDbgPresent=NULL;
HMODULE hK32=GetModuleHandle("KERNEL32.DLL");
if(!hK32) hK32=LoadLibrary("KERNEL32.DLL");
if(hK32) {
IsDbgPresent=(pfnIsDebuggerPresent)GetProcAddress(hK32, "IsDebuggerPresent");
}
FoolProcDump();
ScrewWithVirtualPC();
unsigned long lStartTime=GetTickCount();
if(IsBPX(&IsBPX)) {
#ifdef DBGCONSOLE
g_cConsDbg.Log(5, "Breakpoint set on IsBPX, debugger active.../n");
#endif // DBGCONSOLE
m_bIsDebug=true; return true;
}
if(IsBPX(&IsSICELoaded)) {
#ifdef DBGCONSOLE
g_cConsDbg.Log(5, "Breakpoint set on IsSICELoaded, debugger active.../n");
#endif // DBGCONSOLE
m_bIsDebug=true; return true;
}
if(IsBPX(&IsSoftIceNTLoaded)) {
#ifdef DBGCONSOLE
g_cConsDbg.Log(5, "Breakpoint set on IsSoftIceNTLoaded, debugger active.../n");
#endif // DBGCONSOLE
m_bIsDebug=true; return true;
}
if(IsBPX(&IsVMWare)) {
#ifdef DBGCONSOLE
g_cConsDbg.Log(5, "Breakpoint set on IsVMWare, debugger active.../n");
#endif // DBGCONSOLE
m_bIsDebug=true; return true;
}
if(IsSoftIceNTLoaded()) {
#ifdef DBGCONSOLE
g_cConsDbg.Log(5, "SoftIce named pipe exists, maybe debugger is active.../n");
#endif // DBGCONSOLE
m_bIsDebug=true; return true;
}
if(IsSICELoaded()) {
#ifdef DBGCONSOLE
g_cConsDbg.Log(5, "SoftIce is loaded, debugger active.../n");
#endif // DBGCONSOLE
m_bIsDebug=true; return true;
}
// if(IsVMWare()) {
//#ifdef DBGCONSOLE
// g_cConsDbg.Log(5, "Running inside VMWare, probably honeypot.../n");
//#endif // DBGCONSOLE
// m_bIsDebug=true; return true;
// }
if(IsDbgPresent) {
if(IsBPX(&IsDbgPresent)) {
#ifdef DBGCONSOLE
g_cConsDbg.Log(5, "Breakpoint set on IsDebuggerPresent, debugger active.../n");
#endif // DBGCONSOLE
m_bIsDebug=true; return true;
}
if(IsDbgPresent()) {
#ifdef DBGCONSOLE
g_cConsDbg.Log(5, "IsDebuggerPresent returned true, debugger active.../n");
#endif // DBGCONSOLE
m_bIsDebug=true; return true;
}
}
if((GetTickCount()-lStartTime) > 5000) {
#ifdef DBGCONSOLE
g_cConsDbg.Log(5, "Routine took too long to execute, probably single-step.../n");
#endif // DBGCONSOLE
m_bIsDebug=true; return true;
}
#endif // WIN32
return false;
#endif // _DEBUG
}
8.
Calculating TCP/IP checksum in assembler to gain speed
/*
This calculates a TCP/IP checksum
*/
#ifdef WIN32
#define USE_ASM
#endif // WIN32
unsigned short checksum(unsigned short *buffer, int size) {
unsigned long cksum=0;
#ifdef USE_ASM
unsigned long lsize=size;
char szMMBuf[8], *pMMBuf=szMMBuf;
__asm {
FEMMS
MOV ECX, lsize // ecx=lsize;
MOV EDX, buffer // edx=buffer;
MOV EBX, cksum // ebx=cksum;
CMP ECX, 2 // size<2;
JS CKSUM_LOOP2 // goto loop 2
CKSUM_LOOP:
XOR EAX, EAX // eax=0;
MOV AX, WORD PTR [EDX] // ax=(unsigned short*)*buffer;
ADD EBX, EAX // cksum+=(unsigned short*)*buffer;
SUB ECX, 2 // size-=2;
ADD EDX, 2 // buffer+=2;
CMP ECX, 1 // size>1
JG CKSUM_LOOP // while();
CMP ECX, 0 // if(!size);
JE CKSUM_FITS // fits if equal
CKSUM_LOOP2:
XOR EAX, EAX // eax=0;
MOV AL, BYTE PTR [EDX] // al=(unsigned char*)*buffer;
ADD EBX, EAX // cksum+=(unsigned char*)*buffer;
SUB ECX, 1 // size-=1;
ADD EDX, 1 // buffer+=1;
CMP ECX, 0 // size>0;
JG CKSUM_LOOP2 // while();
CKSUM_FITS:
MOV cksum, EBX // cksum=ebx;
MOV EAX, cksum // eax=cksum;
SHR EAX, 16 // eax=cksum>>16;
MOV EBX, cksum // ebx=cksum;
AND EBX, 0xffff // ebx=cksum&0xffff;
ADD EAX, EBX // eax=(cksum>>16)+(cksum&0xffff);
MOV EBX, EAX // ebx=cksum;
SHR EBX, 16 // ebx=cksum>>16;
ADD EAX, EBX // cksum+=(cksum>>16);
MOV cksum, EAX // cksum=EAX;
FEMMS
}
#else // USE_ASM
while(size>1) { cksum+=*buffer++; size-=2; }
if(size) cksum+=*(unsigned char*)buffer;
cksum=(cksum>>16)+(cksum&0xffff);
cksum+=(cksum>>16);
#endif // USE_ASM
return (unsigned short)(~cksum); }
*/
VC++反调试
最新推荐文章于 2020-08-18 20:50:00 发布