Log in

View Full Version : declspec (naked) usage in dll


OHPen
August 16th, 2008, 06:39
Heyho,

actually i prepare a new unwrapping dll for my nucleus framework.
In this dll i want to use assembler:

code looks something like this:

Code:

/* system includes */
#include <windows.h>

/* nucleus includes */
#include <nucleus_dll.h>

BOOL
WINAPI
DllMain(HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpReserved)
{
/* local function variables */
DWORD entry_point = 0xDEADBEEF;
/* ----------------------------- */

switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
MessageBox(NULL, "DLL_PROCESS_ATTACH -> nucleus_dll.dll", "Info", 0);
asm_get_entry_point(&entry_point);
MessageBox(NULL, "DLL_PROCESS_ATTACH -> nucleus_dll.dll", "Info", 0);
break;

case DLL_THREAD_ATTACH:
break;

case DLL_THREAD_DETACH:
break;

case DLL_PROCESS_DETACH:
break;
}

return TRUE;
}

__declspec (naked)
void
asm_get_entry_point(DWORD* entry_point)
{
__asm
{
mov esi, dword ptr fs:[0]
rkmh_checkNextEntryInSEHList:
lodsd
cmp eax, 0FFFFFFFFh
je rkmh_lastSEHEntryFound
mov esi, eax
jmp rkmh_checkNextEntryInSEHList
rkmh_lastSEHEntryFound:
mov edi, dword ptr[esi + 4]
and edi, 0FFFF0000h
rkmh_stepBackToFindKernel32MZHeader:
cmp word ptr[edi], 'ZM'
jz rkmh_MZHeaderFound
sub edi, 10000h
jmp rkmh_stepBackToFindKernel32MZHeader
rkmh_MZHeaderFound:
mov ebx, edi
add ebx, [ebx].e_lfanew
cmp word ptr[ebx],'EP'
je rkmh_Kernel32ModuleHandleFound
sub edi, 10000h
jmp rkmh_stepBackToFindKernel32MZHeader
rkmh_Kernel32ModuleHandleFound:
mov eax, edi
add eax, [eax].e_lfanew
add eax, 4
xor ebx, ebx
mov bx, word ptr [eax + 20]
cmp ebx, IMAGE_NT_OPTIONAL_HDR32_MAGIC
je rkmh_32bit
jmp rkmh_64bit
rkmh_32bit:
nop
int 3
jmp finished
rkmh_64bit:
nop
jmp finished
finished:
ret 4
}
}


I want to use the asm_get_entry_point_functino as declspec naked. And please don't mention that the asm_.... function does not return the entry_point right now, i know that
From the compiler and linking perspective everything works fine. No complains about syntax or similar stuff.
When the dll is loaded the first MessageBox is displayed and then the dll exits.
Instead it should execute the asm_... function.

Any idea whats the problem in this case ?

Regards,

OHPen

PS: Usually i prefere pure highlevel code or pure assembler. i never got used to inline assembler

Neitsa
August 16th, 2008, 08:15
Hi,

Quote:
[Originally Posted by "MSDN"]
For functions declared with the naked attribute, the compiler generates code without prolog and epilog code. You can use this feature to write your own prolog/epilog code sequences using inline assembler code


As your function has no prologue and a RET, the main function is simply returning. In other words :

Code:

// cut

switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
MessageBox(NULL, "DLL_PROCESS_ATTACH -> nucleus_dll.dll", "Info", 0);

//execute asm_get_entry_point func.

return;

/* unreachable code */

MessageBox(NULL, "DLL_PROCESS_ATTACH -> nucleus_dll.dll", "Info", 0);
break;

//cut


Solutions :

- Remove naked attribute

or

- Leave naked attribute and write a func prologue (simple stack frame init like ENTER or PUSH EBP and MOV EBP, ESP).

IMHO, using InLoadOrderModuleList (see PEB_LDR_DATA struct) is faster to find the k32 base address (no loop) or entry points of loaded modules in process address space.

OHPen
August 16th, 2008, 11:03
Hi Neitsa,

thank you for your suggestions. I tried leaving the declspec (naked) and together with fixing some other stuff (stack was crap) it now works.

But a small question remains: I don't understand what you meant with the function simply returns. I understand if there is no return assembled than the function would simply continue with trying the next byte to interprete as opcode. But that could not be the problem in my case because i had a ret instruction at the end. What a possible problem could be is that there would be a wrong return address on stack at the end of the function. And that really was the problem. Only thing i didn't understand is, that immediatly after i enter the asm_... function, i took a look at the stack to verify return address. And the address in front of me was definitvely not the correct return address.

How can the return address be wrong immediatly after calling the function ? The return address is pop onto the stack by the processor, so no interference possible....and even if the stack was fuXXored before this should not result in such a behaviour, right ?

Maybe i should make a small break. I simply don't get it
Regards,

OHPen

DeepBlueSea
August 16th, 2008, 12:51
In your naked function you are spoiling registers that should be saved.
IMHO that would be ESI, EDI, EBX, and EBP that should always be saved across every function call on common x86 calling conventions. Since you are writing a naked function, the compiler doesnt do that for you.

EDIT: Oh, it was a wrong return address? I don't see how this could happen. But if you are debugging this you clearly have to see where the wrong return address originates from.

EDIT2: Ok, i just tried it myself. Used ur exact function in a DLL with a Messagebox before and after. It works fine. Both MessageBoxes are shown.

OHPen
August 16th, 2008, 13:40
@DeepBlueSea: Yeah i know if you reproduce it like that you have a different basis like i have, because this dll is manually loaded in a target process. Anyway, another problem probably was that i tend to kill every process i don't know on my winxp in order to save resources. And after installing BoundsCheckerSuite and kill such a for me unknown process, my debug environment really behaved strange. For example visual studio didn't restore software breakpoints at all, it just overwrote the origianl opcode without restoring, och
does not work well, hehe. after a restart and my personal agreement not to kill any boundscheck injection processes, everything seems to work fine.
Moreover i decided not to manually retrieve the EP of the target, i now force the user of the framework to setup an xml file with the needed information. this makes it more easier for me to code and i don't have 1000s of console parameters.

Regards,

OHPen

Neitsa
August 16th, 2008, 20:04
Quote:
[Originally Posted by "OHPen"]
Maybe i should make a small break. I simply don't get it


Sorry, I really don't know what I was thinking about when posting this answer... Yep, you're absolutely right, the RET will return from the asm proc, not from the DllMain...

Glad to see it works now.

Time for me to take a vacation now.

OHPen
August 17th, 2008, 06:24
No problem, neitsa, it was just to clarify that I'm not totally stupid and trust me there are moment i really think: "What the hell, ...."

Regards,

OHPen

omega_red
August 20th, 2008, 07:06
A little offtopic, but I guess it can be helpful to share.
If you use naked/inline asm functions (bad, since it's not portable to x64 in any way , disable incremental linking in the project settings. Why?

Say, you have a function:

Code:
__declspec(naked) DWORD DoStuff()
{
__asm
{
// stuff
}
}


And then you inject this function into another process by VirtualAllocEx WriteProcessMemory CreateRemoteThread. It should work fine, right? But with incremental linking enabled, compiler creates a jump table for all functions, and when you use DoStuff symbol in the code, it doesn't point at your function directly, but at the stub jmp in the table. So, a call like
Code:
WriteProcessMemory(hProc, remoteAddr, DoStuff, size, 0);

..won't work: it will write the jump table into another process, and not your function.

And yes, it was pretty frustrating bug to find.

OHPen
August 20th, 2008, 09:35
@omega: nice but isn't that same i used in my first snipped ?