Log in

View Full Version : Terminal Dogma: "the whole crackme is ANTI trace!"


ZaiRoN
May 8th, 2003, 13:38
Hi ALL!
For those who they are not interested in the sentinel's project I would like to suggest this interesting crackme. Here is the readme file:

--------- Terminal Dogma -----------

Brought to you by AndreaGeddon
www.andreageddon.8m.com
andreageddon@hotmail.com

BEFORE YOU RUN IT: THIS CRACKME IS XP ONLY (AND A BIT 2K)!
I coded this crackme aiming to all-win-compatibility, that is, i wanted it
to run on every win (9x-me-nt-2k-xp). Due to several bugs in the interface
i use (three bugs among all os versions) this crackme runs ONLY ON XP!
Writing and testing this crackme was really hard, so i didnt try to fix it
(elicz words: "hey, you know whom to bug" )
However, you can try to run it on 2K (some versions are compatible), it
could have some little problem, but at least you can trace it (and that is
just what i want!). I advise NOT to run it on 9x/me, it may crash the
system .

Dont worry, i didnt put in the crackme ring0 stuff or other dangerous code
to intentionally crash the system, on nt/2k/xp there are not system problems,
only crackme problems! However if you experience undesired crash i'm sorry,
it's not intentional

HOW IT WORKS: AIM OF THE CRACKME
When you launch the crackme you should see three textboxes with text inside
and a button, pressing the button you should see a messagebox telling "not
registered". The aim of the crackme is to patch it so it will appear the
messagebox telling "you are registered". Simple!
Note: YOU ARE ALLOWED TO PATCH ONLY ONE BYTE
Its really easy, there is only a jump to patch. Its in a crypted section, but
the crypting function is only a xor, so you dont have to face layers on layers
of decription!
Why am i telling you all this? Because you just have to figure out how the
crackme works! Once you understand it, patching requires only one minute!
However, i think that you will have to think a while before understanding the
engine of this crackme, i hope you'll find it interesting!
Note: if you run on 2k it will not display the messagebox, also if you can hear
the relative "ding". Thats a problem of winsta, when you understand the crackme
you also should understand the problem However you can still try to trace
the crackme!

FEATURES
-What you can use:
All the tools of the world!
-What tools are useful:
Only softice (and ida)

The crackme has:
- Anti debug/anti trace (not tricks, the whole crackme is ANTI trace!)
- A cripted section (the decript function is only a xor
and the xorkey is given, however decrypting the whole
block is NOT simple as you could think!) I called the encryption
system "selective crypting"
uhm thats all! As i told you, use just softice and ida, other tools
arent useful

ps. normally after 3 seconds of inactivity the crackme closes, its normal!

Enjoy it!
AndreaGeddon

--------- Terminal Dogma -----------

Good luck
ZaiRoN

ps. The crackme is solvable even if you have win9x (only using ida), trust me

sv
May 9th, 2003, 06:54
Hi zairon

Thanks, it was a very interesting one!
Good work AndreaGeddon

regards

ZaiRoN
May 9th, 2003, 15:44
Hi sv,
Quote:
it was a very interesting one!
Nice to see your words. Yes, the idea is VERY interesting!

How have you solved the crackme? I wrote a little idc script. Have you stepped all the code (instruction by instruction ) ? Have you used a strange and original way?

ZaiRoN

sv
May 10th, 2003, 02:53
Hi ZaiRoN


I have coded a little asm proggy to decrypt code section and i have used OllyDbg to found 'the byte'

idc script is a nice way !

sv

evaluator
May 15th, 2003, 16:11
i like unpacking..don't know ida..

ZaiRoN
May 16th, 2003, 11:22
Hi ALL!

Ok, maybe it's time to start with some explanation of what the crackme does.

The file is not packed and/or encrypted but the first part of the crackme seems to be a loader, that's strange :-)
Code:
004010B9 mov esi, ds:LoadLibraryA
004010BF push edi
004010C0 push offset aUser32_dll ; lpLibFileName = user32.dll
004010C5 mov [esp+39Ch+var_381], 0
004010CA xor ebp, ebp
004010CC call esi ; call LoadLibraryA
004010CE push offset aKernel32_dll ; lpLibFileName = kernel32.dll
004010D3 mov dword_4086B0, eax
004010D8 call esi ; call LoadLibraryA
004010DA mov edi, ds:GetProcAddress
004010E0 mov dword_4086B4, eax
004010E5 xor esi, esi

004010E7 mov ecx, dword_406108[esi] ; select the handle to DLL module: user32 or kernel32
004010ED mov eax, dword_408720[esi] ; eax points to the name of the current function
004010F3 push eax ; lpProcName
004010F4 mov edx, [ecx]
004010F6 push edx ; hModule
004010F7 call edi ; GetProcAddress
004010F9 mov dword_4086B8[esi], eax ; it saves the addresses starting from 4086B8
004010FF add esi, 4
00401102 cmp esi, 38h
00401105 jl short loc_4010E7 ; this cycle is executed 14 times
This snippet is used to retrieve 10 functions's address. These functions are:

GetModuleHandleA
LoadCursorA
RegisterClassA
CreateWindowExA (5 times)
DefWindowProcA
GetMessageA
TranslateMessage
DispatchMessageA
ExitProcess
MessageBoxA

Some of these functions are already imported by the crackme and we really don't know the reason for which the crackme has gone to the search of these functions.

After that, the crackme creates a new file named akira.exe and fills it with 3072 bytes; these bytes are taken from the crackme itself, starting from 405278. The new file (an executable) has 3 sections: "code", "data" and ".idata"; no resource section. The only instructions in the file are:
Code:
CODE:00401000 push 0
CODE:00401002 call $+5
CODE:00401007 jmp ds:ExitProcess
Nothing interesting for the moment.
When the file is fully created we found the first interesting function, CreateProcess:
Code:
004011A2 lea eax, [esp+398h+hProcess]
004011A6 lea ecx, [esp+154h]
004011AD push eax ; lpProcessInformation
004011AE push ecx ; lpStartupInfo
004011AF push 0 ; lpCurrentDirectory
004011B1 push 0 ; lpEnvironment
004011B3 push 5 ; dwCreationFlags: DEBUG_PROCESS & CREATE_SUSPENDED
004011B5 push 1 ; bInheritHandles
004011B7 push 0 ; lpThreadAttributes
004011B9 push 0 ; lpProcessAttributes
004011BB lea edx, [esp+1B8h]
004011C2 push 0 ; lpCommandLine
004011C4 push edx ; lpApplicationName: "...\Akira.exe"
004011C5 call ds:CreateProcessA
This function creates a new process and the new process is the file Akira.exe. The interesting things is represented by the two creation flags:
- DEBUG_PROCESS: the calling process is treated as a debugger and the new process is a process being debugged
- CREATE_SUSPENDED: the primary thread of the new process is created in a suspended state, and does not run until the ResumeThread function is called.

Well, TerminalDogma is the debugger and Akira is the launched process!

The first part of the crackme is ended. It's also ended my little initial explanation, I hope to see someone else interested to discover how the debugger will work and how akira.exe will be changed...

best regards,
ZaiRoN

evaluator
May 16th, 2003, 13:18
If you need help, ask questions..

ZaiRoN
May 16th, 2003, 15:43
Hi evaluator,

are you talking to me? No thanks
I have written the message to try to animate the conversation; I did not want to attach my idc script without giving explanations because this area is been created to learn something new and I am sure it might help someone out there. I know that many people does not post messages for *fear*, I only took the initiative
Everything here...

ciao,
ZaiRoN

evaluator
May 17th, 2003, 12:12
that was joke..
I forgot smile

ZaiRoN
May 30th, 2003, 12:53
It's time to go on!
As I said before, "TerminalDogma is the debugger and Akira is the launched process!", ok.

Akira is resumed using ResumeThread and, after that, the *infinite* loop used by TerminalDogma to debug Akira will start:
Code:
.text:00401223 push 0BB8h ; dwMilliseconds: 3 seconds
.text:00401228 push edx ; lpDebugEvent
.text:00401229 call ds:WaitForDebugEvent ; WaitForDebugEvent
.text:0040122F test eax, eax
.text:00401231 jz loc_401680
.text:00401237 mov eax, [esp+0F4h] ; eax = dwDebugEventCode
.text:0040123E dec eax
.text:0040123F jz short loc_401254
.text:00401241 sub eax, 4
...
This is the initial part of the debug loop. The function WaitForDebugEvent waits for debug events; the crackme will close itself whether nothing will happen in the next 3 seconds.
Code:
BOOL WaitForDebugEvent(
LPDEBUG_EVENT lpDebugEvent, // address structure DEBUG_EVENT for event information
DWORD dwMilliseconds // number of milliseconds to wait for event
);

typedef struct _DEBUG_EVENT {
DWORD dwDebugEventCode; // Specifies a debugging event code that identifies the type
of debugging event
DWORD dwProcessId; // Specifies the identifier of the process in which the
debugging event occurred
DWORD dwThreadId; // Specifies the identifier of the thread in which the
debugging event occurred
union {
; additional information relating to the debugging event
} u;
} DEBUG_EVENT;
At 401237, TerminalDogma retrieves the debugging event code received. The programs is only interested in two types of event:
- EXCEPTION_DEBUG_EVENT (= 1): this is received when an exception occurs in the debuggee process (Akira). If this event is received we will jump at 401254
- EXIT_PROCESS_DEBUG_EVENT (=5): a thread in the debugee process exits...

The interesting exception is the first one: EXCEPTION_DEBUG_EVENT. When this type of exception is received, the crackme checks the exact type of the exception:
Code:
.text:00401254 mov eax, [esp+100h]
.text:0040125B cmp eax, 80000003h ; 80000003=STATUS_BREAKPOINT=EXCEPTION_BREAKPOINT
.text:00401260 jz loc_401580
.text:00401266 mov ecx, [esp+1Ch]
.text:0040126A cmp eax, 80000004h ;80000004=STATUS_SINGLE_STEP=EXCEPTION_SINGLE_STEP
.text:0040126F lea eax, [esp+398h+lpBaseAddress]
.text:00401273 mov [esp+398h+lpBaseAddress], 10007h
.text:0040127B push eax
.text:0040127C push ecx
.text:0040127D jz loc_4013B5
The crackme checks for these types:
EXCEPTION_BREAKPOINT: a breakpoint was encountered (int3...)
EXCEPTION_SINGLE_STEP: we will have this exception after the execution of each instruction.

I won't put all the crackme's instructions but, I will only tell you what will happen whether EXCEPTION_BREAKPOINT or EXCEPTION_SINGLE_STEP has been received.

The first exception received by TerminalDogma is EXCEPTION_BREAKPOINT; it's only a debug break (int 3), it occurs before Akira executes its first instruction. In this case, TerminalDogma will perform a ContinueDebugEvent and the "core of the crackme" begins.
From now to the end of the program, TerminalDogma receives this sequence of exceptions: singlestep, breakpoint, singlestep, breakpoint, singlestep...and so on.
- As I said before, single step exception is received after the execution of a single Akira's instruction. SingleStep handler, using WriteProcessMemory, writes an CCCCCCCCh dword inside Akira at address 401000h (the address of the next instruction that Akira will execute); as you can understand, TerminalDogma places an int3! After that, TerminalDogma calls ContinueDebugEvent and another instruction from Akira will be executed.
- This will raise an exception_breakpoint caught by the other handler that starts at 401580. This handler decrypts a single instruction, using the simple xor-decryption scheme mentioned by AndreaGeddon, and writes (using WriteProcessMemory) the new instruction inside Akira at address 401000h (the address of the next instruction that Akira will execute). After that, ContinueDebugEvent is called.

Every instruction is decrypted at runtime and executed at the same address: 401000h. The crackme is all here, I think it's interesting, don't you think?
Now that you know, how is it possible to solve the crackme? :-)

Ciao,
ZaiRoN

orp
December 1st, 2006, 03:01
what prevents one from logging the debugger process to grab all instructions that are written to the debugee

this can easy be done by hooking WriteProcessMemory

and how do you handle conditional jumps, or jumps generally?

Ricardo Narvaja
December 1st, 2006, 19:23
Donīt run in xp sp2 SPANISH VERSION with all actualizations

Ricardo