# ANTIDEBUG1
### `CFF_EXPLORER`

_ Nghe tên bài là chúng ta có thể thấy đây là một bài antidebug.
---
### **IDA PRO**

_ Khi ném file vào IDA để tiến hành phân tích, theo kinh nghiệm mình thấy hàm `TLSCallBack_0` , hàm này sẽ chạy trước hàm `WinMain` của chúng ta nên chúng ta sẽ tiến hành đọc nó trước.
### `Flow hàm TLSCallBack`

- Chúng ta có thể thấy hai hàm khá lạ là `sub_401df0` và `sub_401f10`, sau khi chương trình gọi 2 hàm này ra với các hằng số tương ứng thì chúng sẽ trả lại cho chúng ta một địa chỉ để call một hàm nào đó, mình sẽ đặt breakpoint tại đoạn sau hai hàm này thực thi xong để xem có gì xảy ra:

- Khi đã chạy được đến breakpoint mình xem thử kết quả được trả về (`Thanh ghi EAX`) :

- Vậy là sau khi chạy xong hai hàm này chúng trả lại cho chúng ta hàm `ZwQueryInformationProcess` được lấy từ `PEB` của process.
- Vậy chúng ta có thể đổi lại tên hàm cho hai hàm này để có thể dễ hiểu hơn:

#### `ZwQueryInformationProcess`
- Tiếp tục tiến hành phân tích, luồng của chương trình sau khi đã có hai hàm resolver API, `ZwQueryInformationProcess` là một hàm antidebug,hàm này sẽ lấy thông tin của một process (` có thể là chính nó`) để check xem process này có đang bị debug hay không,`ZwQueryInformationProcess` cũng giống `NtQueryInformationProcess` nhưng chỉ khác là `Zw` sẽ được gọi từ `kernel mode`:
```asm=
lea eax, [dwReturned]
push eax ; ReturnLength
push 4 ; ProcessInformationLength
lea ecx, [dwProcessDebugPort]
push ecx ; ProcessInformation
push 7 ; ProcessInformationClass
push -1 ; ProcessHandle
call NtQueryInformationProcess
inc dword ptr [dwProcessDebugPort]
jz being_debugged
...
being_debugged:
push -1
call ExitProcess
```
---
`CÒN CỦA CHÚNG TA:`
```asm=
push ebp
mov ebp, esp
push ecx
mov ecx, 7B3FA1C0h
call resolver_init
mov edx, 5A3BB3B0h
mov ecx, eax
call resolve_final
mov [ebp-4], eax
push eax
mov eax, esp
push 0
push 4
push eax
push 7
push 0FFFFFFFFh
call [ebp-4] ;ZwQueryInformationProcess
pop eax
test eax, eax
jnz short being_debug
jmp short default
being_debug:
lea eax, unk_95018
add eax, 0Ah
mov byte ptr [eax], 74h ; 't'
default:
mov esp, ebp
pop ebp
retn 0Ch
```
- Vậy luồng đúng của chương trình sẽ giống như thế này :
```asm=
push ebp
mov ebp, esp
push ecx
mov ecx, 7B3FA1C0h
call resolver_init
mov edx, 5A3BB3B0h
mov ecx, eax
call resolve_final
mov [ebp-4], eax
push eax
mov eax, esp
push 0
push 4
push eax
push 7
push 0FFFFFFFFh
call [ebp-4] ;ZwQueryInformationProcess
pop eax
test eax, eax
jmp short default
default:
mov esp, ebp
pop ebp
retn 0Ch
```
---
#### Data changed
- Khi bị debug thì nó sẽ thay đổi data tại vùng nhớ `unk_95018 + 10`.Mình sẽ đổi tên nó thành `g_data`. Tiếp tục phân tích hàm `WinMain`:
```C=
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
HACCEL v4; // esi
HANDLE CurrentProcess; // eax
HWND Window; // eax
HWND v7; // esi
struct tagMSG Msg; // [esp+8h] [ebp-2Ch] BYREF
HANDLE TokenHandle; // [esp+24h] [ebp-10h] BYREF
DWORD ReturnLength; // [esp+28h] [ebp-Ch] BYREF
HACCEL TokenInformation; // [esp+2Ch] [ebp-8h] BYREF
v4 = 0;
TokenHandle = 0;
CurrentProcess = GetCurrentProcess();
if ( OpenProcessToken(CurrentProcess, 8u, &TokenHandle) )
{
ReturnLength = 4;
if ( GetTokenInformation(TokenHandle, TokenElevation, &TokenInformation, 4u, &ReturnLength) )
v4 = TokenInformation;
}
if ( TokenHandle )
CloseHandle(TokenHandle);
if ( !v4 )
{
MessageBoxA(0, "Please run the program with administrator right", "Warning", 0);
exit(1);
}
LoadStringW(hInstance, 0x67u, &WindowName, 100);
LoadStringW(hInstance, 0x6Du, &ClassName, 100);
sub_91260(hInstance);
::hInstance = hInstance;
Window = CreateWindowExW(0, &ClassName, &WindowName, 0xCF0000u, 0x80000000, 0, 0x80000000, 0, 0, 0, hInstance, 0);
v7 = Window;
if ( !Window )
return 0;
ShowWindow(Window, nShowCmd);
UpdateWindow(v7);
TokenInformation = LoadAcceleratorsW(hInstance, (LPCWSTR)0x6D);
while ( GetMessageW(&Msg, 0, 0, 0) )
{
if ( !TranslateAcceleratorW(Msg.hwnd, TokenInformation, &Msg) )
{
TranslateMessage(&Msg);
DispatchMessageW(&Msg);
}
}
return Msg.wParam;
}
```
- Hàm `WinMain` gọi `CreateWindowExW` vậy nên luồng chính sẽ nằm ở `hInstance` mà `hInstance` được khởi tạo từ hàm `sub_91260`:
```C=
__thiscall sub_91260(HINSTANCE hInstance)
{
WNDCLASSEXW v2; // [esp+0h] [ebp-34h] BYREF
v2.cbSize = 48;
v2.style = 3;
v2.lpfnWndProc = sub_91350;
v2.cbClsExtra = 0;
v2.cbWndExtra = 0;
v2.hInstance = hInstance;
v2.hIcon = LoadIconW(hInstance, (LPCWSTR)0x6B);
v2.hCursor = LoadCursorW(0, (LPCWSTR)0x7F00);
v2.hbrBackground = (HBRUSH)6;
v2.lpszMenuName = (LPCWSTR)109;
v2.lpszClassName = &ClassName;
v2.hIconSm = LoadIconW(v2.hInstance, (LPCWSTR)0x6C);
return RegisterClassExW(&v2);
}
```
- Vậy luồng chính sẽ nằm trong `sub_91350`:
```C=
LRESULT __stdcall sub_91350(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
const CHAR *v5; // [esp-Ch] [ebp-258h]
DWORD pdwDataLen; // [esp+0h] [ebp-24Ch] BYREF
struct tagPAINTSTRUCT Paint; // [esp+4h] [ebp-248h] BYREF
__int128 v8[2]; // [esp+44h] [ebp-208h] BYREF
__int128 v9; // [esp+64h] [ebp-1E8h]
char v10[208]; // [esp+74h] [ebp-1D8h] BYREF
CHAR input[260]; // [esp+144h] [ebp-108h] BYREF
v8[0] = xmmword_938D0;
v8[1] = xmmword_938E0;
v9 = xmmword_938F0;
memset(v10, 0, sizeof(v10));
pdwDataLen = 48;
if ( Msg <= 0xF )
{
switch ( Msg )
{
case 0xFu:
BeginPaint(hWnd, &Paint);
EndPaint(hWnd, &Paint);
return 0;
case 1u:
sub_912F0(hWnd);
return 0;
case 2u:
PostQuitMessage(0);
return 0;
}
return DefWindowProcW(hWnd, Msg, wParam, lParam);
}
if ( Msg != 273 )
return DefWindowProcW(hWnd, Msg, wParam, lParam);
switch ( (unsigned __int16)wParam )
{
case 4u:
GetWindowTextA(::hWnd, input, 256);
if ( check(input) )
{
sub_91000((BYTE *)input, &pdwDataLen);
if ( pdwDataLen >= 0x2E )
{
BYTE14(v9) = 0;
MessageBoxA(0, (LPCSTR)v8, "OK", 0);
return 0;
}
v5 = "Wrong";
}
else
{
v5 = "Wrong check fail";
}
MessageBoxA(0, "oh, no", v5, 0);
return 0;
case 0x68u:
DialogBoxParamW(hInstance, (LPCWSTR)0x67, hWnd, DialogFunc, 0);
return 0;
case 0x69u:
DestroyWindow(hWnd);
return 0;
default:
return DefWindowProcW(hWnd, 0x111u, wParam, lParam);
}
}
```
- Tại `case 4` chúng ta thấy chương trình lấy `input` (`GetWindowTextA(::hWnd, input, 256)`)
### Phân tích hàm `check` :
```C=
char __thiscall check(const char *this)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
if ( strlen(this) < 0x26 )
return 0;
sub_91FD0((__m128i *)v25, g_data[(unsigned __int8)g_data[4] / 0xCu + 4]);
v2 = v24;
v3 = 0;
....
```
- Chúng ta có thể thấy `g_data` mà chương trình thay đổi ở hàm `TLSCallBack` ( nếu bị debug ) đã được sử dụng ở đây. Mình không tác động từ `input` vào được đến hàm này nên mình sẽ bỏ qua và mình chỉ quan tâm output mình nhận được sẽ là gì nên mình sẽ chỉ để ý đến output(ở đây sẽ là biến`v25`).Mình sẽ đổi tên `v25` thành `default_const` để dễ nhận dạng. Tiếp tục phân tích chương trình:
```C=
....
while ( 2 )
{
switch ( dword_932C8[v3] )
{
case 1:
v4 = dword_93360[v3];
v5 = this[dword_933F8[v3]];
v24 = NtCurrentPeb()->NtGlobalFlag & 0x70;
v6 = sub_92050(v24 == 112, (int)v25, v4);
v7 = v26;
if ( v26 >= 256 )
v7 = 0;
v26 = v7 + 1;
v2 = byte_9329F[v7 + 1] == (char)(v5 ^ v6);
goto LABEL_9;
case 2:
v8 = sub_91600(this[dword_933F8[v3]], (int)v25, dword_93360[v3]);
goto LABEL_8;
.....
```
- Vòng lặp `While True` và chương trình sẽ switch theo case data `dword_932C8` nên mình sẽ đổi tên nó thành `program` , tương ứng ở đây `v3` sẽ là `index`:
```C=
while ( 2 )
{
switch ( program[index] )
{
case 1:
```
- Ta thấy tại `case 1` chương trình đã sử dụng một kĩ thuật antidebug. Và đọc tiếp thì chúng ta dễ dàng nhận thấy cứ mỗi case trong `switch case` này sẽ đều sử dụng một kĩ thuật antidebug nên mình sẽ đi phân tích từng case một theo thứ tự:
#### CASE 1

- Nếu đọc theo luồng của chương trình thì địa chỉ `Input` của chúng ta nhập vào vẫn đang nằm ở thanh ghi `edi` và chương trình sẽ lấy từng kí tự chúng ta nhập vào ví trí là data tại `ds:dword_933F8[esi]` , `esi` đang là `index` mà chúng ta đã đặt tên cho mã giả ở bên trên. Đổi tên để dễ đọc hơn :

##### **NtGlobalFlag**
```asm=
mov eax, large fs:30h ; Get PEB
mov al, [eax+68h]
and al, 70h
mov [ebp-239h], al
cmp byte ptr [ebp-239h], 70h ; 'p'
```
- Chương trình lấy `PEB` và sau đó lấy `NtGlobalFlag` bên trong `PEB`, `NtGlobalFlag` là `flag` được setup khi tiến trình được chạy bởi `debugger`, khi bị debug `NtGlobalFlag` sẽ được set giá trị là `0x70`. Vậy luồng đúng của `Case 1` này sẽ theo đường màu xanh :

- lúc này `dl` sẽ được set giá trị là 0 và được sử dụng ở hàm `sub_92050` :

- Hàm `sub_92050` này nhận vào 3 tham số đầu vào là `dl` (`giá trị check debug`), `default_const` (giá trị đầu ra ở hàm đã sử dụng `g_data`) và cuối cùng là giá trị ở `g_const[index]`:

- Mình tiếp tục không quan tâm `sub_92050` sẽ làm gì vì mình không tác động được từ `input` vào hàm này và sau cùng hàm này sẽ chỉ trả lại cho mình một const data nên mình sẽ để tên hàm này là `gen_const`:
```C=
while ( 2 )
{
switch ( program[index] )
{
case 1:
v4 = g_const[index];
p_input = input[index_table[index]];
v24 = NtCurrentPeb()->NtGlobalFlag & 0x70;
v6 = gen_const(v24 == 112, (int)default_const, v4);
v7 = v26;
if ( v26 >= 256 )
v7 = 0;
v26 = v7 + 1;
v2 = byte_9329F[v7 + 1] == (char)(p_input ^ v6);
goto LABEL_9;
```
- Chúng ta lại thấy sau khi `gen_const` xong chúng ta sẽ xor rồi so sánh với cipher tại `byte_9329F[v7 + 1]` nên mình sẽ đổi tên `byte_9329F` => `cipher`. Vậy ở case này nếu chúng ta đi đúng chúng ta sẽ phải set giá trị của tham số thứ nhất của `gen_const` thành 0 ( không bị `debug` ). Và lấy giá trị vừa `gen_const` đó xor lại với cipher là chúng ta sẽ có được input đúng, như vậy sau `case 1` này chúng ta có thể đoán được rằng tất cả các case còn lại cũng sẽ có một kiểu flow tương tự như vậy.
#### CASE 2

- Lại tiếp tục là sử dụng resolver api, tiến hành debug để xem hàm chúng ta nhận được sau cùng là gì:

##### Heap Flags
- `Heap Flags` chứa hai cờ được khởi tạo cùng với `NtGlobalFlag`: `Flags` và `ForceFlags`.
- Sau `resolved` sẽ là hàm `GetVersion`. Sau đó lấy `PEB` và lấy giá trị tại field `0x18`:

- Vậy là lấy chương trình sẽ lấy `ProcessHeap` và chương trình sử dụng hàm `GetVersion` để lấy `Flags` và `ForceFlags` tùy vào version.
- Ở 32-bit Windows NT, Windows 2000 và Windows XP , `flags` nằm ở offset `0x0C` của Heap. Ở 32-bit Windows Vista và mới hơn nữa, cờ này nằm ở offset `0x40`
- Ví dụ như trong trường hợp của chúng ta, mình sử dụng phiên bảo Window mới. Nên khi thử debug chúng ta sẽ thấy `Flags` nằm ở `0x40` và `ForceFlags` nằm ở `0x44`:

- Khi debug `ForceFlags` được setup nhờ những cờ sau đây được setup:
```C=
HEAP_TAIL_CHECKING_ENABLED (0x20)
HEAP_FREE_CHECKING_ENABLED (0x40)
HEAP_VALIDATE_PARAMETERS_ENABLED (0x40000000)
```
- Với `Flags` :
```C=
;ở Windows NT, Windows 2000 và 32-bit Windows XP:
HEAP_GROWABLE (2)
HEAP_TAIL_CHECKING_ENABLED (0x20)
HEAP_FREE_CHECKING_ENABLED (0x40)
HEAP_SKIP_VALIDATION_CHECKS (0x10000000)
HEAP_VALIDATE_PARAMETERS_ENABLED (0x40000000)
;ở 64 bit Windows XP, Window Vista hoặc phiên bản mới hơn:
HEAP_GROWABLE (2)
HEAP_TAIL_CHECKING_ENABLED (0x20)
HEAP_FREE_CHECKING_ENABLED (0x40)
HEAP_VALIDATE_PARAMETERS_ENABLED (0x40000000)
```
- Trong Case thứ 2 này, Chúng ta có thể thấy chương trình đang check `Flags(0x40)` của chúng ta và phiên bản window của mình mới hơn nên nó sẽ giống như :
```C=
Flags(0x40) = HEAP_GROWABLE(2)|HEAP_TAIL_CHECKING_ENABLED(0x20)|HEAP_FREE_CHECKING_ENABLED(0x40)|HEAP_VALIDATE_PARAMETERS_ENABLED (0x40000000)
=>>> Flags(0x40) = 0x40000062
```
- Vậy để Bypass đoạn này chúng ta sẽ SetIP cho chương trình đến luồng không bằng với `0x40000062` :

- Lại flow quen thuộc ở case 1 :

#### CASE 3

- Tiếp tục đặt debug và thấy hàm sau resolve lại là `GetVersion` nhưng thay vì case 2 chúng ta lấy `Flags(0x40)` thì lần này chương trình lấy `ForceFlags(0x44)`.
- Bypass như case số 2 :

#### CASE 4
- Case 4 dài hơn nên chúng ta sẽ đi từng chút một

- Có 3,4 lần resolve, sau khi debug chúng ta được :

- Sửa vào mã giả C chúng ta được như sau:
```C=
bool __usercall mw_case_4(char a1, DWORD *a2, int a3)
{
v4 = resolver_init((void *)0x6AE69F02);
GetProcessHeap = (int (*)(void))resolve_final((int)v4, 1089880685);
v6 = (HANDLE)GetProcessHeap();
v7 = resolver_init((void *)0x7B3FA1C0);
ntdll_memset = (void (__cdecl *)(PROCESS_HEAP_ENTRY *, _DWORD, int))resolve_final((int)v7, 2073848310);
ntdll_memset(&HeapEntry, 0, 28);
v9 = resolver_init((void *)0x6AE69F02);
HeapWalk = (void (__stdcall *)(int, PROCESS_HEAP_ENTRY *))resolve_final((int)v9, 1883853620);
while ( HeapEntry.wFlags != 4 )
HeapWalk((int)v6, &HeapEntry);
v11 = (char *)HeapEntry.lpData + HeapEntry.cbData;
v12 = 0;
while ( 1 )
{
v13 = *v11++;
if ( v13 != (char)0xAB )
break;
if ( ++v12 >= 8 )
{
v14 = 1;
goto LABEL_8;
}
}
v14 = 0;
LABEL_8:
v15 = gen_const(v14, (int)a2, a3);
if ( (int)a2[139] >= 256 )
a2[139] = 0;
++a2[139];
return cipher[a2[139]] == (char)(a1 ^ v15);
}
```
- Sau khi tìm hiểu thì nếu như `HEAP_TAIL_CHECKING_ENABLED` có được khởi tạo trong `NtGlobalFlag` thì những byte `0xABABABAB` sẽ được thêm vào cuối của những vùng nhớ heap được phân ra. Còn nếu `HEAP_FREE_CHECKING_ENABLED` được khởi tạo thì những byte`0xFEEEFEEE` sẽ được thêm vào cuối của những vùng nhớ rỗng cho tới khi gặp đc vùng nhớ heap mới.
- Tham khảo thêm (https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-process_heap_entry)
- Vậy để Bypass chúng ta sẽ sửa flow chương trình theo hình :

#### CASE 5

- Debug để resolve lại hết API chúng ta được :
```C=
char __usercall mw_case_5(unsigned __int8 a1, DWORD *a2, int a3)
{
v4 = resolver_init((void *)0x6AE69F02);
CreateToolhelp32Snapshot = (int (__stdcall *)(MACRO_TH32CS, _DWORD))resolve_final((int)v4, 1040992138);
snapshot = (HANDLE)CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if ( snapshot == (HANDLE)-1 )
return 1;
processEntry.dwSize = 0x22C;
v8 = resolver_init((void *)0x6AE69F02);
Process32First = (int (__stdcall *)(HANDLE, PROCESSENTRY32W *))resolve_final((int)v8, 645722533);
if ( !Process32First(snapshot, &processEntry) )
return 1;
v10 = resolver_init((void *)0x6AE69F02);
Process32Next = (int (__stdcall *)(HANDLE, PROCESSENTRY32W *))resolve_final((int)v10, 42915264);
v11 = resolver_init((void *)0x6AE69F02);
CloseHandle = (void (__stdcall *)(HANDLE))resolve_final((int)v11, 1332537868);
while ( !check_name((char *)processEntry.szExeFile) )
{
if ( !Process32Next(snapshot, &processEntry) )
{
v13 = 0;
goto LABEL_9;
}
}
v13 = 1;
LABEL_9:
v14 = gen_const(v13, (int)a2, a3);
if ( (int)a2[139] >= 256 )
a2[139] = 0;
if ( cipher[++a2[139]] == (a1 ^ (unsigned __int8)v14) )
{
CloseHandle(snapshot);
return 1;
}
else
{
CloseHandle(snapshot);
return 0;
}
}
```
- Đoạn code trên sẽ lấy tên tất cả process ra để check xem có đang bị debug không. Vậy nên bypass chương trình tương tự như các case trên
#### CASE 6

- Debug để resolve API ta được:

- Mã giả C :
```C=
bool __usercall sub_91AA0@<al>(char a1@<dl>, DWORD *a2@<ecx>, int a3)
{
v5 = resolver_init(&unk_2489AAB);
BlockInput = (int (__stdcall *)(int))resolve_final((int)v5, 838910877);
v7 = BlockInput(1);
v8 = BlockInput(1);
if ( byte_955B8 ) // byte_955B8 ban đầu = 0
{
if ( v7 == v8 )
goto LABEL_3;
}
else if ( v7 != v8 )
{
LABEL_3:
v9 = gen_const(1, (int)a2, a3);
byte_955B8 = 1;
goto LABEL_6;
}
v9 = gen_const(0, (int)a2, a3);
LABEL_6:
if ( (int)a2[139] >= 256 )
a2[139] = 0;
++a2[139];
return cipher[a2[139]] == (char)(a1 ^ v9);
}
```
- Đoạn code trên có những đoạn khá hiển nhiên và để bypass chúng ta sẽ sửa như sau :
```C=
bool __usercall sub_91AA0@<al>(char a1@<dl>, DWORD *a2@<ecx>, int a3)
{
v5 = resolver_init(&unk_2489AAB);
BlockInput = (int (__stdcall *)(int))resolve_final((int)v5, 838910877);
v7 = BlockInput(1);
v8 = BlockInput(1);
v9 = gen_const(1, (int)a2, a3);
if ( (int)a2[139] >= 256 )
a2[139] = 0;
++a2[139];
return cipher[a2[139]] == (char)(a1 ^ v9);
}
```
#### CASE 7

- Resolved:

- Lại là `NtQueryInformationProcess` Bypass:

### Giải Bài
- sau tất cả các case chúng ta thấy rằng chương trình sẽ đều `gen_const` và sinh ra giá trị để xor với input của chúng ta, sau đó so sánh với cipher. Vậy `gen_const` nhận vào tham số thứ 1 :
- `data check debug (1 hoặc 0)`
- `default_const`(Generated ở bên trên hàm check_Hàm đã sử dụng data thay đổi ở TLSCallback)
- `g_const`
- Vậy thì để giải bài mình sẽ bật debug và lấy nguyên si `default_const` đã generate ở bên trên:

- Sau đó mình sẽ mô phỏng lại y hệt chương trình đã chạy theo từng `switch case` :
- Code mình giải viết trên `DEV-C++`
```C=
#include<stdio.h>
#define _DWORD unsigned __int32
#define _WORD unsigned __int16
char gen_const(char a1, unsigned __int8 *a2, int a3)
{
int v4; // esi
char v6; // bl
int v7; // ecx
unsigned __int16 v8; // dx
unsigned int v9; // edx
char v10; // cl
unsigned int v11; // edx
unsigned __int8 v12; // al
bool v13; // zf
unsigned __int8 *v14; // ecx
int v15; // esi
char v16; // dl
int v18; // [esp+14h] [ebp+8h]
v4 = a3 - 1;
v18 = 171;
v6 = 0;
do
{
if ( v4 <= 5 )
{
if ( *(_DWORD *)&a2[4 * v4 + 16] )
v8 = *(_WORD *)&a2[4 * v4 + 16];
else
v8 = *(_WORD *)&a2[4 * v4];
v7 = (v8 >> 1) | (unsigned __int16)(((unsigned __int16)(32 * v8) ^ (v8 ^ (unsigned __int16)(4 * (v8 ^ (2 * v8)))) & 0xFFE0) << 10);
*(_DWORD *)&a2[4 * v4 + 16] = v7;
}
else
{
v7 = 0;
}
v9 = v7 & 0x7FF;
v10 = v7 & 7;
v11 = v9 >> 3;
if ( a1 )
v12 = a2[v11 + 44];
else
v12 = ~a2[v11 + 44];
v13 = v18-- == 1;
a2[v11 + 44] = v12 ^ (1 << v10);
}
while ( !v13 );
v14 = a2 + 46;
v15 = 64;
do
{
v16 = *(v14 - 2);
v14 += 4;
v6 ^= *(v14 - 4) ^ *(v14 - 3) ^ *(v14 - 5) ^ v16;
--v15;
}
while ( v15 );
return v6;
}
int main(){
unsigned __int32 index_table[] = {9, 18, 15, 3, 4, 23, 6, 7, 8, 22, 10, 11, 33, 13, 14, 27, 16, 37, 17, 19, 20, 21, 5, 34, 24, 25, 26, 2, 12, 29, 30, 31, 32, 28, 0, 35, 36, 1};
unsigned __int32 g_const[] = {1, 3, 1, 1, 2, 1, 3, 1, 2, 2, 4, 4, 1, 3, 4, 4, 4, 1, 2, 1, 4, 1, 4, 3, 1, 2, 4, 4, 2, 2, 1, 3, 4, 2, 1, 2, 2, 3};
unsigned __int8 default_const[] = {54,236,0,0,54,237,0,0,54,187,0,0,54,140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,95,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
unsigned __int8 cipher[] = {14,235,243,246,209,107,167,143,61,145,133,43,134,167,107,219,123,110,137,137,24,149,103,202,95,226,84,14,211,62,32,90,126,212,184,16,194,183,0,0};
unsigned __int32 program[] = {6, 1, 7, 1, 3, 2, 4, 3, 6, 3, 7, 6, 1, 4, 7, 4, 1, 5, 7, 6, 7, 5, 6, 4, 5, 1, 7, 5, 2, 3, 1, 2, 3, 2, 1, 6, 2, 4};
unsigned char tmp;
unsigned char flag[40];
for(int i=0;i<38;i++){
switch(program[i]){
case 1:
tmp = gen_const(0,default_const,g_const[i]);
flag[index_table[i]] = cipher[i]^tmp;
break;
case 2:
tmp = gen_const(1,default_const,g_const[i]);
flag[index_table[i]] = cipher[i]^tmp;
break;
case 3:
tmp = gen_const(1,default_const,g_const[i]);
flag[index_table[i]] = cipher[i]^tmp;
break;
case 4:
tmp = gen_const(0,default_const,g_const[i]);
flag[index_table[i]] = cipher[i]^tmp;
break;
case 5:
tmp = gen_const(0,default_const,g_const[i]);
flag[index_table[i]] = cipher[i]^tmp;
break;
case 6:
tmp = gen_const(1,default_const,g_const[i]);
flag[index_table[i]] = cipher[i]^tmp;
break;
case 7:
tmp = gen_const(1,default_const,g_const[i]);
flag[index_table[i]] = cipher[i]^tmp;
break;
default:
break;
}
}
printf("%s",flag);
return 1;
}
```
- Kết quả Input đúng sẽ là : `I_10v3-y0U__wh3n Y0u=c411..M3 Senor1t4`.