Jump to content
Tuts 4 You

My debugger loads dll too late


Pancake

Recommended Posts

Hello :)


So today i decided to create own debugger for own use, everything works just fine btu as we all know the anti-debug tricks have to by bypassed. So i created my Fix.dll which fixes the peb and hooks far jump (currently only for wow64). It works like a charm and spoofs the Zw* functions output, but the problem is that the dll is loaded too late..


 


After receiving the first debug meesage which is obviously CREATE_PROCESS_DEBUG_EVENT i get the EIP, LoadLibraryA address and then inject payload which loads my Fix.dll (i coped the shellcode from StrongOD). So it calls LoadLibraryA for my dll and returns to the original EIP, continuing execution properly without any error. But DllMain (or DLL_PROCESS_ATTACH) isnt called at this time! Why? I receive many debug events about loading/unloading some DLLs, then one Memory Breakpoint exception, and after that my DLL finally ran. But its too late. Themida detects me before my DLL did anything BUT i load it with the very first CREATE_PROCESS_DEBUG_EVENT...


 


Why is that? Is there something i miss? Or should i let the program


 


Thanks in advance for help!


Edited by Pancake
Link to comment

How cool that you replied Aguila :) Thanks.


 


Okay i got the system breakpoint thingy. But now i think i messed the far jump hook. Damn need to review the asm code of it, its much harder than it seemed! But im tryin very hard BY MYSELF :)


 


Is it enough to set eax/ecx/edx for far jump? Or esp must also be set to edx + 8 (so edx contains params and esp is edx and return from far jump and return from Zw func)? The esp facks the simplicity of previous solution. i see that the syscalls which doesnt require to be modified are handled and returnin correctly, but when im tryin to fake the result i got some mess with registers on exit.. T_T


 


Well there is no need to write all the anti anti from the scratch :) I will use your dll. But which files from the scyllahide pack should i  load at system breakpoint? Injecting just hooklibraryx86.dll does not work and injector cli seems not to hook he far jump...


Edited by Pancake
Link to comment

The DLL entry point will only be called after some of the other DLLs are loaded (like kernel32, ntdll, etc.) The way you could go is manually loading your DLL and then setting the instruction pointer from the system breakpoint (before that you won't have any kernel functions to use). Like Aguila says, ScyllaHide handles this stuff.

Just a quick thing that might help your development process (a lot!):

 

1. Set x64dbg as your JIT Debugger

2. When you need to see what is going on, manually push the current instruction pointer to the stack and then set the instruction pointer to a newly allocated page with the following code in it:

int3ret
3. Call DebugActiveProcessStop and let x64dbg catch the JIT event.

4. Press Ctrl+F8 over the int3 instruction (completely skipping it), then step in the RET and you can debug wherever you left off :)

Here is some code I wrote a time ago (TitanEngine specific, but should be easy to understand):

 

void ArmaDebugger::DetachAndBreak(){    void* remote = VirtualAllocEx(fdProcessInfo->hProcess, 0, 0x1000, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE);    if(!remote)    {        cbError("VirtualAllocEx failed!");        StopDebug();        return;    }    unsigned char code[] = {0xCC, 0xC3};    if(!WriteProcessMemory(fdProcessInfo->hProcess, remote, code, sizeof(code), 0))    {        cbError("WriteProcessMemory failed!");        StopDebug();        return;    }    ULONG_PTR csp = GetContextData(UE_CSP);    csp-=sizeof(ULONG_PTR);    ULONG_PTR cip = GetContextData(UE_CIP);    if(!WriteProcessMemory(fdProcessInfo->hProcess, (void*)csp, &cip, sizeof(remote), 0))    {        cbError("WriteProcessMemory failed!");        StopDebug();        return;    }    SetContextData(UE_CSP, csp);    SetContextData(UE_CIP, (ULONG_PTR)remote);    if(!DetachDebuggerEx(fdProcessInfo->dwProcessId))    {        cbError("DetachDebuggerEx failed!");        StopDebug();        return;    }    cbLog("Detached from process!");}
Hope that helps,

EDIT: With some plugin work it could also be done the other way around (from x64dbg to your debugger).

Mr. eXoDia

Edited by Mr. eXoDia
Link to comment

See here for timing:


https://bitbucket.org/NtQuery/scyllahide/src/fca4927b641f5ff7680b47efda8db144bd12363c/ScyllaHideOlly1Plugin/ScyllaHideOlly1Plugin.cpp?at=master


 


ScyllaHide does not use LoadLibrary for dll loading, because this is not stealth. It manually maps it to the process. The dll is seen as shellcode.


 


For Themida you also need the special PEB handling, see documentation in section 4.2 Special PEB Fix Information

Link to comment

Okay but i already told that i wrote own debuger from scratch for own purpose, to easly add finctionality from c++ etc (and im NOT goin to use ollydbg here), but i wanted to use the scyllahide plugin for stealth, and thats the biggest problem.


I know all the Zw functions antidebug, PEB etc, I dont really care how scyllahide works "under the hood" because im very happy with the plugin in olly, but right now i need to make it work with my own code, and neither hooklibraryx86 works or CLIInjector.exe also does not hook the far jumps.


Dont ask me why im writing own debugger, i just felt like i need simple one of my own.. :)


Edited by Pancake
Link to comment

i know the manual mapping, used it several times. This time tho i got to set EIP to the dllmain instead of creating a thread with it. Still i would like to make the syscall hooking by myself but the ammount of asm and little details here is overwhelming... :) Obviously im not goin to make inline hooks on the entry points of selected Zw functions because its detectable and checked by packers as far as i know so i gotta think of a solution similar to scyllahide. By the way i couldnt find the far jump hook ( i mean the asm code which is responsible for handling fs:[C0] call )in the scylla sources, where is it located?


Edited by Pancake
Link to comment

I seem unable to set any HWBP in my target... So i tried to launch clean olly in my own debuger ( so i know there are no anti dbg tricks inside ), and when i receive memory breakpoint for the first time which is the system breakpoint i do



        CONTEXT ctx = { 0 };
        ctx.ContextFlags = CONTEXT_FULL;
        if (!GetThreadContext(pi.hThread, &ctx)) printf("GTC FAIL %X\n", GetLastError());
        DWORD old;
        LPVOID address = VirtualAllocEx(pi.hProcess, 0, sizeof(payload), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
        if (!WriteProcessMemory(pi.hProcess, address, payload, sizeof(payload), &old) || sizeof(payload) != old) printf("WRITE FAIL %X\n", GetLastError());         ctx.Dr0 = 0x401000; //hardcoded EP of olly
        //ctx.EFlags |= 0x100; // i even tried trap flag which does not throw the exceptions...
        ctx.Dr7 = 0x55; // well 0x1 doesnt work too
        ctx.Dr6 = 0;
        if (!SetThreadContext(pi.hThread, &ctx)) printf("STC FAIL %X\n", GetLastError());
        getchar(); // so i can see output in console
        return DBG_CONTINUE;

And im NOT gettin ANY single step exception, i should be gettin at least the printf from OnSingleStep() function.



DWORD OnDebugEvent(const LPDEBUG_EVENT de){     switch (de->u.Exception.ExceptionRecord.ExceptionCode)
    {
    case EXCEPTION_ACCESS_VIOLATION:
        return OnAccessViolation(de);
    case EXCEPTION_BREAKPOINT:
        return OnMemBp(de);
    case EXCEPTION_DATATYPE_MISALIGNMENT:
        return OnDatatypeMissalignment(de);
    case EXCEPTION_SINGLE_STEP:
        return OnSingleStep(de);
    default:
        return OnOtherException(de);
    }
}

I noticed that i can switch EIP easly with setthreadcontext, but debug registers seem not to work in my case... Why?


Edited by Pancake
Link to comment

Well i used debug registers many times and its always 0x55 for execute dr0-3. And here it does not work... and i got no damn idea why is that...

 

Aha and it does not explain why EFlags also did not work

 

OKAY i resolved it.

Isnt it funny how MISLEADING name "CONTEXT_FULL" is? So it turns out that "FULL" isnt that full ....

 

#define CONTEXT_CONTROL         (CONTEXT_i386 | 0x00000001L) // SS:SP, CS:IP, FLAGS, BP
#define CONTEXT_INTEGER         (CONTEXT_i386 | 0x00000002L) // AX, BX, CX, DX, SI, DI
#define CONTEXT_SEGMENTS        (CONTEXT_i386 | 0x00000004L) // DS, ES, FS, GS
#define CONTEXT_FLOATING_POINT  (CONTEXT_i386 | 0x00000008L) // 387 state
#define CONTEXT_DEBUG_REGISTERS (CONTEXT_i386 | 0x00000010L) // DB 0-3,6,7
#define CONTEXT_EXTENDED_REGISTERS  (CONTEXT_i386 | 0x00000020L) // cpu specific extensions#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER |\
                      CONTEXT_SEGMENTS)

 

 

So the answer is

#define CONTEXT_FULLY_FULL CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS

works, well "fully full" XD

Edited by Pancake
Link to comment

Hello again. First of all huge thanks for Aguila who helped me to solve basic anti-anti problems. Now i can launch any file, or should i say ALMOST any file. I noticed something weird about one exe. Analyzin it in olly i noticed that it has encrypted DLL file in one section, which after being unpacked is fixed in memory (fixed i mean done relocations imports etc) and then LoadLibraryExA(dllname, 0, 0) is called. The file is NOT dumped in the folder and LoadLibrary loads it just fine, why is that? And back to debugger, olly properly displays that dll has been loaded and continues normal execution (olly shows path of dll as it would be in same folder as the exe) while my debugger does not get the LOAD_DLL_DEBUG_EVENT notifcation and soon gets the debugee termination message. I already checked that DLL is properly loaded when ran under by debugger, so why didnt i get notified? Did someone experience similar problem?


 


http://i.imgur.com/uLDjRYl.png


Left is output from my dbg and right is olly. U can see the exact same flow and then missing DLL notification which i think results in the termination.


Thanks in advance


Edited by Pancake
Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...