News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Jump table question

Started by donkey, April 28, 2011, 08:56:19 PM

Previous topic - Next topic

donkey

Hi Jeremy,

I was wondering how I could get (at run-time) the address of the jump table entry for an API function. For clarification, when GoAsm calls say GetModuleHandleA it actually calls an address in a jump table that usually looks like

push 0
call 0x00409000
...
00409000: jmp     D[hInstance+0x926c (0040926c)]


The following will obtain the true address of GetModuleHandleA (0x74E51245)

push [GetModuleHandleA]
pop eax


Examining the code shows that the PUSH [GetModuleHandleA] encodes as PUSH [0x0040926c], which I assume is the address of the "fixed up" procedure entry point in the jump table. What I am looking for is the address of the JMP instruction (0x00409000) since I am looking to map the symbol based on the CALL instruction, is there an easy way to get this address at run-time ?

Edgar
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

lingo


     mov eax, dword ptr [DispatchMessage+2] ; eax->jmp address of DispatchMessage
     mov ESI, [eax]                         ; esi->real addres of DispatchMessage API
     ....
     ....
     ....
   
MsgLoop:
    invoke GetMessage, addr msg, 0,0,0
    test eax, eax
    je ExitProcess
    invoke TranslateMessage, addr msg
    PUSH      MSG 
    CALL      ESI     ; call DisapatchMessage API
    jmp MsgLoop

dedndave

        mov     eax,GetModuleHandleA

:P

jorgon

Hi Edgar
Unfortunately mov eax,GetModuleHandle throws up an error.

However this works:-

MyLabel: CALL [SendMessageA]
;
START:
MOV EAX,[MyLabel+2]
RET


The code at MyLabel is never actually called, it just serves as a code label.
The code at "START" should load (in your example) the value 40926Ch.

Is this what you are after?

Author of the "Go" tools (GoAsm, GoLink, GoRC, GoBug)

dedndave

hi Jeremy
it works with masm

donkey

Quote from: jorgon on April 29, 2011, 08:14:23 AM
Hi Edgar
Unfortunately mov eax,GetModuleHandle throws up an error.

However this works:-

MyLabel: CALL [SendMessageA]
;
START:
MOV EAX,[MyLabel+2]
RET


The code at MyLabel is never actually called, it just serves as a code label.
The code at "START" should load (in your example) the value 40926Ch.

Is this what you are after?



That's perfect, thanks Jeremy. I'll have to figure out how to get it done dynamically. It shouldn't be too much of an issue as I know that GetModuleHandle should always be the first entry in the table (with GetProcAddress second) I will be able to locate the jump table and use that to unravel the imports and get the data I need.

Quote from: dedndave on April 29, 2011, 11:35:17 AM
hi Jeremy
it works with masm

Hey Dave,

Two different assemblers I'm afraid, there are many things that GoAsm does that would give MASM fits and vice versa. Jeremy never designed GoAsm to be MASM compatible.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

dedndave

Quote...GetModuleHandle should always be the first entry in the table (with GetProcAddress second)

is that always the case ?
i would like to be able to locate the table for an idea i had - to work backwards and find the strings   :P

i can locate one, then step backwards, but that isn't very clean - lol
it would be nice to find the base of the table easily

donkey

Hi Dave,

I have never seen a PE file without those as the first two entries, at worst they will be in the first few so if you find the lower page boundary of the entry you should be at the start of the jump table. But AFAIK they are always 1 & 2. If your looking for the strings, they are not there, at least not in the executable once the PE loader is done. You can use SymFromAddr but I am desperately trying to solve an "Invalid Parameter" error that is dogging the function for me. As it is I have enumerated all possible calls in all loaded modules and sorted them by entry point (its actually pretty fast) and am searching for the entry in the array by address. I can post a snippet if you like.

I believe that MASM defines a symbol for each import in the form user32!GetDlgItem, you can get that symbol through a dump of the symbol table. Try my debug tool for RadAsm and use DumpSymbols to check it.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

dedndave

by all means, Edgar - post the snippet - maybe someone can provide a fresh look at it   :bg

i looked inside an exe...
i didn't assemble with any special switches

ml /c /coff OSInfo30.asm
polink /SUBSYSTEM:WINDOWS  /OPT:NOREF OSInfo30.obj OSInfo30.res

i am pretty sure i get the same result using Link

my thinking was - you could make a neat little error reporting routine with the strings that are already there   :bg

jump tables:


strings:


the attachments are the above PNG images renamed to ZIP

donkey

Hi Dave,

They are in the PE but are they in the memory image of the running process ? I have always assumed they were discarded by the PE loader once they have been located and fixed.

Mmmm. The definition for SYMBOL_INFO at msdn is:

typedef struct _SYMBOL_INFO {
 ULONG   SizeOfStruct;
 ULONG   TypeIndex;
 ULONG64 Reserved[2];
 ULONG   Index;
 ULONG   Size;
 ULONG64 ModBase;
 ULONG   Flags;
 ULONG64 Value;
 ULONG64 Address;
 ULONG   Register;
 ULONG   Scope;
 ULONG   Tag;
 ULONG   NameLen;
 ULONG   MaxNameLen;
 TCHAR   Name[1];
} SYMBOL_INFO, *PSYMBOL_INFO;


Now if you count the bytes, you come up with 81 bytes. However, if you do as MS does in its examples and pass SIZEOF SYMBOL_INFO in the buffer for SymFromAddr, you get the "Invalid Parameter" error. On inspection of the output from dbghelp, SizeOfStruct should be set to 88 bytes, though I have no idea where they get that number from. There is at least one member missing from the definition for 32 bits, one of the ULONG parameters is actually a ULONG64 though I haven't found which one yet, this could be an alignment issue though, its just very difficult to check the parameters to see if they are valid.

At any rate I've been working out the kinks in SymByAddr and hopefully I can use that function eventually but for now I am building my own table like this:

SYMBOLENTRY struct
Name DB 64 DUP
Module DB 32 DUP
Address DQ ?
Type DD ?
ends

GetSymbols FRAME DbgType
LOCAL hProcess:%HANDLE

// Use common controls DPA, this will be replaced with a more
// efficient array once testing is done, for now its reliable and
// one less thing to debug.
invoke DPA_CreateEx,32,NULL
mov [hSymbols],eax

// You can just use -1 in place of hProcess
invoke GetCurrentProcess
mov [hProcess],eax

// Initialize. invade the process and load all modules
invoke SymInitialize,[hProcess],0, TRUE
// Enumerate everything (usually over 13,000 symbols)
invoke SymEnumSymbols,[hProcess],0,0,"*!*",offset SymEnumSymbolsProc, [DbgType]
// Shut it down
invoke SymCleanup,[hProcess]

// Sort the symbols by address
invoke DPA_Sort,[hSymbols],offset SortSymbolTable,0

ret
endf

SymEnumSymbolsProc FRAME pSymInfo, SymbolSize, UserContext
uses edi,ebx
LOCAL mbi:MEMORY_BASIC_INFORMATION
LOCAL SymModInfo:IMAGEHLP_MODULE64

mov edi,[pSymInfo]
add edi,4

// Get the protection for this symbol
invoke VirtualQuery,[edi+SYMBOL_INFO.Address],offset mbi,SIZEOF MEMORY_BASIC_INFORMATION
mov eax,[mbi.Protect]

mov D[SymModInfo.SizeOfStruct],SIZEOF IMAGEHLP_MODULE64
invoke SymGetModuleInfo64,-1,[edi+SYMBOL_INFO.Address],[edi+SYMBOL_INFO.Address+4],offset SymModInfo
lea edx,SymModInfo
add edx,IMAGEHLP_MODULE64.ModuleName
lea eax,edi+SYMBOL_INFO.Name
invoke AddSymbolToTable,eax,edx,[edi+SYMBOL_INFO.Address],[edi+SYMBOL_INFO.Address+4],[mbi.Protect]

.EXIT
mov eax,TRUE
RET
ENDF

AddSymbolToTable FRAME pszSymbol, pszModule, pSymbol, pSymbolHi,iType
uses ebx

invoke GlobalAlloc,GMEM_FIXED,SIZEOF SYMBOLENTRY
mov ebx,eax

invoke lstrcpyn,ebx,[pszSymbol],63
lea eax,ebx+SYMBOLENTRY.Module
invoke lstrcpyn,eax,[pszModule],31
mov eax,[pSymbol]
mov [ebx+SYMBOLENTRY.Address],eax
mov eax,[pSymbolHi]
mov D[ebx+SYMBOLENTRY.Address+4],eax
mov eax,[iType]
mov [ebx+SYMBOLENTRY.Type],eax

invoke DPA_InsertPtr,[hSymbols],DPA_APPEND,ebx
ret
endf

SortSymbolTable FRAME pItem1,pItem2,lParam

// Sort the array by SYMBOLENTRY.Address
mov eax,[pItem1]
mov eax,[eax+SYMBOLENTRY.Address]
mov ecx,[pItem2]
mov ecx,[ecx+SYMBOLENTRY.Address]
cmp eax,ecx
jle >
xor eax,eax
inc eax
ret
:
jl >
xor eax,eax
ret
:
xor eax,eax
dec eax
ret
endf

DestroySymbolTable FRAME pItem, pData
invoke GlobalFree,[pItem]
ret
endf
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

donkey

Well, I have finally got the bugs out of my FindSymbol routine, so all of the above work was for nothing :) The last issue was that unmentioned by the entry at MSDN, you *MUST* use CoTaskMemAlloc to allocate the buffer for SymByAddr, I could not get it to work with GlobalAlloc and it was a tough bug to track down. Here's how to search for a symbol using the DBGHELP api. It also gives the displacement from the symbol found, in this example the symbol found is GetModuleHandleA and the displacement is +5:

push [GetModuleHandleA]
pop eax
add eax,5
invoke FindSymbol,-1,eax

FindSymbol FRAME hProcess, pAddress
LOCAL Displacement:Q
LOCAL pSymInfo:D
LOCAL SymModInfo:IMAGEHLP_MODULE64

invoke CoTaskMemAlloc,SIZEOF SYMBOL_INFO+MAX_SYM_NAME
mov [pSymInfo],eax
mov D[eax+SYMBOL_INFO.MaxNameLen],MAX_SYM_NAME
mov D[eax+SYMBOL_INFO.SizeOfStruct],88

// invade process, load all modules
invoke SymInitialize,[hProcess],0, TRUE

invoke SymFromAddr,[hProcess],[pAddress],0,offset Displacement,[pSymInfo]
mov eax,[pSymInfo]
add eax,SYMBOL_INFO.Name
add eax,4 // The annoying displacement I can't figure out
// EAX points to the symbol name

mov D[SymModInfo.SizeOfStruct],SIZEOF IMAGEHLP_MODULE64
invoke SymGetModuleInfo64,[hProcess],[pAddress],0,offset SymModInfo
lea eax,SymModInfo+IMAGEHLP_MODULE64.ModuleName
// EAX point to the module name (eg Kernel32)

// Shut it down
invoke SymCleanup,[hProcess]
invoke CoTaskMemFree,[pSymInfo]

xor eax,eax
RET

ENDF


Note that this is GoAsm code so QWORDs require 2 pushes, in any MASM translation you can remove the second push.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

MichaelW

#11
For some reason the MSDN structure is different from the structure in the 2003 PSDK.

The Microsoft compilers align the structure according the rules specified here:

http://msdn.microsoft.com/en-us/library/Aa290049

Edit: Added code to display the alignment of the structure, and the 4-byte alignment does not appear to match what the linked article specifies.

Output for the EXE in the attachment, compiled with the Microsoft Visual C++ Toolkit 2003 compiler:

sizeof(si)       88
address of si    12FE8C
alignment of si  4


SizeOfStruct 12FE8C             4
TypeIndex    12FE90     12FE90  4
Reserved     12FE94     12FE94  16
Index        12FEA4     12FEA4  4
Size         12FEA8     12FEA8  4
ModBase      12FEAC     12FEAC  8
Flags        12FEB4     12FEB4  4
Value        12FEBC     12FEB8  8
Address      12FEC4     12FEC4  8
Register     12FECC     12FECC  4
Scope        12FED0     12FED0  4
Tag          12FED4     12FED4  4
NameLen      12FED8     12FED8  4
MaxNameLen   12FEDC     12FEDC  4
Name         12FEE0     12FEE0  1



eschew obfuscation

donkey

Hi Michael,

I'm not quite sure about the output you posted, there are some values that don't make sense to me, for example size of Reserved should be 16 bytes (2 x DQ). I will have to continue my investigation to try to get this thing right. Thanks for the alignment link, however since the only change that has to be made to conform to the requirements is to make Name 4 bytes instead of 1, the structure still presents the same problem, the annoying 4 byte alignment error.

Since your output shows that the Value member is moved ahead 4 bytes I am going to go on the assumption that that is the issue and try it out like this:

typedef struct _SYMBOL_INFO_ {
  ULONG   SizeOfStruct;
  ULONG   TypeIndex;
  ULONG64 Reserved[2];
  ULONG   Index;
  ULONG   Size;
  ULONG64 ModBase;
  ULONG   Flags;
  ULONG   Reserved2; <<<<<<< Added padding
  ULONG64 Value;
  ULONG64 Address;
  ULONG   Register;
  ULONG   Scope;
  ULONG   Tag;
  ULONG   NameLen;
  ULONG   MaxNameLen;
  TCHAR   Name[4]; <<<<<<< Added 3 bytes for alignment
} SYMBOL_INFO_;


The only members of interest with the exception of SizeOfStruct are from Address on and they appear to work so.

EDIT: Flags appears to be correct (shows 0x200 for exports, 0 for internal) so I am going with this as the final structure fix.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

dedndave

QuoteWas due to C using 8 byte packing whereas VB uses 4 byte packing. Inserting a padding long integer before .Flags fixed it.

http://www.boards.ie/vbulletin/showthread.php?t=175286

donkey

Hi Dave,

That appears to be incorrect, my tests have shown that the Flags are only right if the padding is inserted after them, otherwise I don't get the correct value for export symbols just 0 which is not what the output should be (except for internals).
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable