When we call a Windows Function the compiler creates a JUMP to a table.
Each entry into the table is an implib__Function.
Is it possible to remove the jump and directly jumps to the corresponding address into the table?
[0000000140001651] FF25B10C0000 jmp qword ptr [0000000140002308]
[0000000140001657] FF25B30C0000 jmp qword ptr [0000000140002310]
[000000014000165D] FF25B50C0000 jmp qword ptr [0000000140002318]
[0000000140001663] FF25B70C0000 jmp qword ptr [0000000140002320]
[0000000140001669] FF25B90C0000 jmp qword ptr [0000000140002328]
[000000014000166F] FF25BB0C0000 jmp qword ptr [0000000140002330]
[0000000140001675] FF25BD0C0000 jmp qword ptr [0000000140002338]
[000000014000167B] FF25C70C0000 jmp qword ptr [0000000140002348]
0002:00000308 __imp_ExitProcess 0000000140002308 kernel32:KERNEL32.dll
0002:00000310 __imp_GetModuleHandleA 0000000140002310 kernel32:KERNEL32.dll
0002:00000318 __imp_GetCommandLineA 0000000140002318 kernel32:KERNEL32.dll
0002:00000320 __imp_SetThreadErrorMode 0000000140002320 kernel32:KERNEL32.dll
0002:00000328 __imp_GetModuleFileNameA 0000000140002328 kernel32:KERNEL32.dll
0002:00000330 __imp_lstrcpy 0000000140002330 kernel32:KERNEL32.dll
0002:00000338 __imp_CreateDirectoryA 0000000140002338 kernel32:KERNEL32.dll
In the following case
xor ecx,ecx
mov rax,OFFSET @End
mov rdx,OFFSET GetCommandLineA
push rax
push rdx
jmp GetModuleHandleA
mov _hInstance,rax
@End :
The "jmp GetModuleHandleA" will be replaced by a jump to the table "0002:00000310"
What I want is "jmp __imp_GetModuleHandleA 0000000140002310"
Many peoples would tell me that remplacing call with jumps is not a good idea, it will be difficult for debuggers...
But what makes the compiler. It create a call then makes a jump into the table...
Thanks Timo for your quick and good answer. :-*
Sure.
extern __imp_ExitProcess:dword
ExitProcess TEXTEQU <__imp_ExitProcess>
[00000001400015AC] 48B80823004001000000 mov rax,140002308
[00000001400015B6] 488B00 mov rax,qword ptr [rax]
[00000001400015B9] FFD0 call rax
0002:00000308 __imp_ExitProcess 0000000140002308 kernel32:KERNEL32.dll
I have replaced One CALL and ONE jump with TWO MOV and ONE CALL
I hope that all these posts wil help some coders to understand the internal process of the assembler and how the compiler does.
Quote from: Jokaste on October 07, 2017, 06:36:48 PM
Many peoples would tell me that replacing call with jumps is not a good idea, it will be difficult for debuggers...
But what makes the compiler. It create a call then makes a jump into the table...
It is really a bad idea.
This breaks the stack framing and troubles the Frame-based Exception Handling mechanism (__try __except).
The compiler creates the jump table for a different scope than just creating a list of jumps.
A jump table give a location to link locally in the executable, and in the same time a location that could be dynamically updated when the executable will be linked to a DLL at later time.A standard call to a symbol as:
call dll_func1
Is resolved by the linker replacing the symbol 'dll_func1' with the reference in the jump table that exists at time of static link (the static link is when you run the linker as polink) avoiding the error message for inexistent symbol.
Then at run time the loader will write the memory address of the loaded DLL in the jump table.
The flow will be:
call dll_func1 ; make a regular call to an address that exist in our executable
....
;jump table
dll_func1: jmp ; the helper jump instruction
__imp_dll_func1: 0x00000000 ; this location will be replaced by the real address in the DLL by the loader
The use of declaration specifiers allows to avoid jump and call directly the function in the DLL by dereferencing the location '__imp_dll_func1:
void __declspec(dllimport) dll_func1(void);
...
dll_func1(); // Standar call. See below as the compiler translates it after the specifier dllexport is applied
The code will be:
call [__imp_dll_func1] ; dereferences the address at location __imp_dll_func1 avoiding the jump
In the last case the compiler avoid the jump.
Google for jump table for more info. I.e. read this (http://sandsprite.com/CodeStuff/Understanding_imports.html).
Of course pushing the return address and then jumping to the function address is very inefficient compared to a 'call' instruction.
while this works well on a RISC architecture on a CISC is just a time consuming operation.
From PellesC help: Appendix -> Program startup: the true story
QuoteProgram startup: the true story
When the entry point is main, execution will actually begin in a function called mainCRTStartup. This function is located in the C runtime library, and will initialize things like the memory manager, file I/O support, and the argv parameter. Multi-threading will be initialized for the multi-threaded version of the C runtime. If special startup functions have been defined (#pragma startup function), they will be called. When all this is done, mainCRTStartup will call main.
When the entry point is wmain, execution will begin in a function called wmainCRTStartup, but otherwise it is the same process.
When the entry point is WinMain, execution will begin in a function called WinMainCRTStartup. The initialization is almost the same as for mainCRTStartup and wmainCRTStartup, but the arguments to WinMain are different.
When the entry point is wWinMain, execution will begin in a function called wWinMainCRTStartup.
When the entry point is DllMain, execution will begin in a function called DllMainCRTStartup. The initialization is similar to the WinMain case.
An example:
.data
msg DB "Hello ASM",13,10,0
.code
mainCRTStartup PROC C
INVOKE printf, ADDR msg
INVOKE ExitProcess, eax
mainCRTStartup ENDP
END
Thanks Timo & Frankie. Could these posts help every coder to improve himself and his code.
There are programmers that did not make long time at school (me for example; I prefered submarines), it's difficult to write algorythms but use of best instructions is possible.
For example :
MOV RAX,12345678h
NOT RAX
or
XOR RAX,0