# Anti-debug.Timing & assembly instruction (p3)
Khi process được trace trong khi debug, thời gian delay giữa các câu lệnh rất lớn so với thời gian thực thi bình thương.
## 1. RDPMC/RDTSC
Là 2 câu lệnh sử dụng cờ PCE trong thanh ghi CR4.
>RDPMC chỉ được dùng trong Kernel mode
>RDTSC được sử dụng trong user mode. (IDA, x96dbg)
>NOTE: time counting bắt đầu count từ thời điểm gặp rdpmc
```cpp=
bool IsDebugged(DWORD64 qwNativeElapsed)
{
ULARGE_INTEGER Start, End;
__asm
{
xor ecx, ecx
rdpmc
mov Start.LowPart, eax
mov Start.HighPart, edx
}
// ... some work, functions...
// Nếu debbuger step trace hoặc set breakpoint trong đoạn này -> large delay time -> debugger bẹhavior detected.
__asm
{
xor ecx, ecx
rdpmc
mov End.LowPart, eax
mov End.HighPart, edx
}
return (End.QuadPart - Start.QuadPart) > qwNativeElapsed;
}
```
### detect
yara
```yaml=
strings:
$rdtsc = { 0F 31 }
$rdpmc = { 0F 33 }
condition:
uint16(0) == 0x5A4D and any of them
```
## 2. GetLocalTime, GetSystemTime
Tương tự như cách trên nhưng sử dụng Windows API GetLocalTime, GetSystemTime, GetTickCount, timeGetTime, QueryPerformanceCounter
```cpp=
SYSTEMTIME stStart, stEnd;
GetLocalTime(&stStart);
// ... some work functions...
// Nếu debbuger step trace hoặc set breakpoint trong đoạn này -> large delay time -> debugger bẹhavior detected.
GetLocalTime(&stEnd);
```
```cpp=
GetSystemTime(&stStart);
// your code.
GetSystemTime(&stEnd);
```
```cpp=
DWORD dwStart = GetTickCount();
// your code
return (GetTickCount() - dwStart) > dwNativeElapsed;
```
```cpp=
DWORD dwStart = timeGetTime();
// some work
return (timeGetTime() - dwStart) > dwNativeElapsed;
```
```cpp=
LARGE_INTEGER liStart, liEnd;
QueryPerformanceCounter(&liStart);
// your code
QueryPerformanceCounter(&liEnd);
return (liEnd.QuadPart - liStart.QuadPart) > qwNativeElapsed;
```
## 3. ZwGetTickCout/KiGetTickCount
Cả 2 hàm đều sử dụng từ [kernel mode](https://fragglet.github.io/dos-help-files/alang.hlp/x_at_L829d.html).
```cpp=
bool IsDebugged(DWORD64 qwNativeElapsed)
{
ULARGE_INTEGER Start, End;
__asm
{
int 2ah
mov Start.LowPart, eax
mov Start.HighPart, edx
}
// ... some work
__asm
{
int 2ah
mov End.LowPart, eax
mov End.HighPart, edx
}
return (End.QuadPart - Start.QuadPart) > qwNativeElapsed;
}
```
### detect
yara
```yaml=
strings:
$int_2a = { CD 2A }
condition:
uint16(0) == 0x5A4D and $int_2a
```
## bypass
patch các hàm check time = NOPs hoặc set lại giá trị trả về.
# Assembly instructions
## 1. INT 3
Là một interuption được sử dụng như một software breakpoint. Trong trường hợp không có debugger, câu lệnh này sẽ raise EXCEPTION_BREAKPOINT (0x80000003) exception và một exception handler sẽ được gọi.
Nếu có debugger, luồng điều khiển sẽ **không** được đưa tới exception handler để xử lí.
>
```cpp=
__try{
__asm int 3;
return true;
}__except(EXCEPTION_EXECUTE_HANDLER){
return false;
}
```
## 2. INT 2D
Tương tự như INT3, INT 2D cũng sẽ raise EXCEPTION_BREAKPOINT exception.
> Nhưng với INT 2D, Windows sử dụng thanh ghi IP (instruction pointer) như một địa chỉ exception.Nếu EAX = 1, 3, 4; thanh gi IP sẽ tăng thêm 1.
>
## 3. DebugBreak
raise breakpoint exception trên tiến trình hiện tại. Nếu không có debugger, luồng điểu khiển sẽ được xử lí bởi exception handler.
```cpp
__try{
DebugBreak();
}
__except(EXCEPTION_BREAKPOINT){
return false;
}
return true;
```
## 4. ICE
Its opcode is 0xF1, được dùng để phát hiện nếu chương trình bị traced.
## 5. Stack Segment Register
Cũng được dùng để phát hiện single-stepping
> Không có 64bit code version vì thanh ghi SS không được hỗ trợ.
```cpp
bool bTraced = false;
__asm{
push ss
pop ss
pushf // push trap flag on stack
test byte ptr [esp+1], 1 // examine the trap flag
jz movss_not_being_debugged
}
bTraced = true;
movss_not_being_debugged:
// restore stack
__asm popf;
return bTraced;
```
## 6. Instruction counting
Sử dụng debugger handle cho EXCEPTION_SINGLE_STEP exception.
Ta sẽ chèn các hardware breakpoint vào chuỗi code thực thi. Exception từ hardware breakpoint sẽ bị bắt bởi vectored exception handler, ta sẽ sử dụng biến đếm tăng lên 1 mỗi lần bắt được exception. khi chạy đến cuối chuỗi code thực thi, ta sẽ so sánh biến đếm để xác định có bị debug không. Nếu khác -> bị debug.
## 7. POPF và Trap Flag (TF)
| Bit | Mask | Abbreviation | category
| -------- | -------- | -------- | -------- |
| 8 | 0x0100 | TF | Trap flag (single step) | control|
Trap Flag trong thanh ghi Flags, khi TF được set, sẽ raise SINGLE_STEP exception. Tuy nhiên, khi ta trace code, TF sẽ bị clear bởi debugger, nên sẽ không nhảy vào exception hander.
```cpp
__try{
__asm{
pushfd // push Flags register into stack
mov dword ptr [esp], 0x100 // change stack value
popfd // set TF
nop
}
return true;
}__except(GetExceptionCode() == EXCEPTION_SINGE_STEP? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_EXCUTION)
return false;
```
## 8. Instruction prefixes
Lợi dụng cách hoạt động của debugger khi gặp các lệnh prefixes.
Nếu thực thi cùng debugger, sau khi đến byte F3; Debugger skip prefix và nhảy tới câu lệnh INT1.
Nếu chạy mà không có debugger, exeption sẽ raise và luông thực thi sẽ vào exception handler.
```cpp
__try
{
// 0xF3 0x64 disassembles as PREFIX REP:
__asm __emit 0xF3
__asm __emit 0x64
// One byte INT 1
__asm __emit 0xF1
return true;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
return false;
}
```
## bypass:
- Patch với lênh NOP.
## detect
yara
```yaml
strings:
$int3 = { CC }
$intCD = { CD }
$int03 = { 03 }
$int2D = { 2D }
$ICE = { F1 }
$Prefix = { F3 }
$pushss_popss = { 16 17 }
$pushf = { 9C }
condition:
uint16(0) == 0x5A4D and any of them
```
###### tags: `windows-internal` `anti-debug` `rev`