flat assembler
Message board for the users of flat assembler.
Index
> Macroinstructions > Alternative approaches to PE imports |
Author |
|
revolution 06 Jul 2006, 23:08
I once did something similar to this, but it caused two main problems. 1) For larger programs the compilation time is too long because of the "call" macro, and 2) The memory usage is very large because of the redefining of labels and the extra macro expansion. I think it is suitable only for smaller programs.
|
|||
06 Jul 2006, 23:08 |
|
vid 07 Jul 2006, 05:05
it's nice, but not for real projects, if it wouldn't be you, i would start explaining why such thing shouldn't be used
|
|||
07 Jul 2006, 05:05 |
|
Tomasz Grysztar 07 Jul 2006, 08:01
Yeah, it eats very much of memory, but the compilation time is not that bad - perhaps because you get out of memory much earlier than it gets really slow With triple calls to all the standard imports from kernel32 and user32 (there's about 500 functions in each) it still got not that bad compilation time (about of current timing for compiling Fresh project), but consumed terrible amount of 150 MB of RAM.
Now the another alternative I planned to provide here, the modification of standard import macro to support direct-call-to-indirect-jump method for invoking APIs. It would be harder to make it separate all the jumps from imports, but this way it doesn't seem to create any problems anyway: Code: macro import name,[label,string] { common name#.lookup: forward if used label if string eqtype '' local _label dd RVA _label else dd 80000000h + string end if end if common if $ > name#.lookup name#.redundant = 0 dd 0 else name#.redundant = 1 end if name#.address: forward if used label if string eqtype '' __import.#label dd RVA _label else __import.#label dd 80000000h + string end if end if common if ~ name#.redundant dd 0 end if forward if used label & string eqtype '' _label dw 0 db string,0 label: jmp [__import.#label] rb RVA $ and 1 end if } Note that you have to change every "invoke" to "stdcall" on switching to this method! |
|||
07 Jul 2006, 08:01 |
|
Tomasz Grysztar 07 Jul 2006, 08:45
PS. If you've made some own macros, why not share them? Even if they are inefficient, they still may be interesting.
|
|||
07 Jul 2006, 08:45 |
|
revolution 07 Jul 2006, 08:49
Quote: direct-call-to-indirect-jump method |
|||
07 Jul 2006, 08:49 |
|
comrade 07 Jul 2006, 09:02
If you call the the API very often, the direct-call-to-indirect-jump method will result in smaller code: 6 bytes for the indirect-jump, and 5 bytes for each indirect call, VERSUS 6 bytes for each regular FF15 call.
That's how MS import libraries are made - if you check MASM/MSLINK generated code, they always have that level of indirection. |
|||
07 Jul 2006, 09:02 |
|
Tomasz Grysztar 07 Jul 2006, 09:06
Perhaps the best would be to automatically generate either of them depending on whether the given API is called more than 6 times or not.
|
|||
07 Jul 2006, 09:06 |
|
revolution 07 Jul 2006, 11:08
Code size is rarely an issue due to the caches. However because this is calling an API it is unlikely that any optimisation is being applied to that particular section of code. It seems much clearer to me in the debugger to use the direct "call [API]". I never did like the MS way of call-jmp [API].
|
|||
07 Jul 2006, 11:08 |
|
vid 07 Jul 2006, 15:55
Tomasz Grysztar wrote: Perhaps the best would be to automatically generate either of them depending on whether the given API is called more than 6 times or not. how would you make it? Force "invoke" macro and disallow usage of "call [abcd], or how? |
|||
07 Jul 2006, 15:55 |
|
Tomasz Grysztar 07 Jul 2006, 16:18
Rather redefine "call" and use "stdcall" everywhere.
|
|||
07 Jul 2006, 16:18 |
|
vid 07 Jul 2006, 16:41
redefining instructions is not good idea at all. when you write "call [something]", you await call instruction, not jump
|
|||
07 Jul 2006, 16:41 |
|
Tomasz Grysztar 07 Jul 2006, 16:58
It would still be a call instruction, only direct instead of indirect.
As for redefining instructions - for some of us it may be not a good idea, some other may like it. The purpose for which I started this thread is to provide some alternative solutions for those that would prefer to go with something other than the standards. |
|||
07 Jul 2006, 16:58 |
|
Joshua 09 Jul 2006, 18:56
Code: ; IMPORT_NO_IAT = 0 ; ; imp library*,[function*] ; imp.insert macro imp library*,[function*] { common match =Import.#library#.Functions,Import.#library#.Functions \{ match a,Import.Libraries \\{ define Import.Libraries a,<library> \\} match ,Import.Libraries \\{ define Import.Libraries <library> \\} include "%fasminc%\imphinta\"#`library#".inc" ;you can comment this line if you want, it's used to include the hints for the calls \} forward match a b c d,function,,, \{ match e,Import.#library#.Functions \\{ match =, =, =,,b c d \\\{ define Import.#library#.Functions e,<a>,<`function> \\\} match =as =, =, =,,b d \\\{ define Import.#library#.Functions e,<a>,<c> \\\} \\} \} } macro imp.insert { match a,Import.Libraries \{ IMPORT.BUILD.TABLE a \} Import.Libraries equ } macro IMPORT.BUILD.TABLE [library] { common local i if defined i rb 3-(rva $+3) mod 4 if ~defined IMPORT_NO_IAT data 12 forward local u if defined u label library dword label library#.Iat dword match a,Import.#library#.Functions \{ IMPORT.FUNCTION.IAT library,a \} if $ > library#.Iat dd 0 end if end if common end data end if data import forward if defined u dd RVA library#.Offset,0,0,RVA library#.Data,RVA library end if common dd 0,0,0,0,0 end data end if forward local d,e if (~defined library#.Offset | defined d) if defined IMPORT_NO_IAT & defined u label library dword end if label library#.Offset dword match a,Import.#library#.Functions \{ IMPORT.FUNCTION.OFFSET library,a \} if $ > library#.Offset if ~defined i | defined e i = 0 e = 0 end if u = 0 dd 0 end if d = 0 end if forward if defined u library#.Data db `library,0 rb rva $ mod 2 match a,Import.#library#.Functions \{ IMPORT.FUNCTION.DATA library,a \} end if } macro IMPORT.FUNCTION.IAT library*,dummy*,[function*,alias*] { forward local d if used function & (~defined function#.Iat | defined d) label function dword if alias eqtype "" function#.Iat dd RVA function#.Data else function#.Iat dd 80000000h+alias end if d = 0 end if } macro IMPORT.FUNCTION.OFFSET library*,dummy*,[function*,alias*] { forward local d if used function & (~defined function#.Offset | defined d) if defined IMPORT_NO_IAT label function dword end if if alias eqtype "" function#.Offset dd RVA function#.Data else function#.Offset dd 80000000h+alias end if d = 0 end if } macro IMPORT.FUNCTION.DATA library*,dummy*,[function*,alias*] { forward local d if used function & alias eqtype "" & (~defined function#.Data | defined d) label function#.Data byte if defined imphint_#function dw imphint_#function else dw 0 end if db alias,0 rb rva $ mod 2 d = 0 end if } Import.Libraries equ Also automaticly creates IAT, you can define IMPORT_NO_IAT to cancel this. Example: Code: in file1: imp KERNEL32.DLL \ ,ExitProcess \ ,GetCurrentThreadId \ imp USER32.DLL \ ,AttachThreadInput \ ,ClientToScreen \ ,EnumChildWindows \ ,FindWindowEx as "FindWindowExA" \ ,GetAsyncKeyState \ in file2: imp KERNEL32.DLL \ ,ExitProcess \ ;Even tho this is defined twice, it will cause no problems ,GetModuleFileName as "GetModuleFileNameA" \ ,GetPrivateProfileInt as "GetPrivateProfileIntA" \ ,Sleep \ in Main file: imp.insert |
|||
09 Jul 2006, 18:56 |
|
Ancient One 14 Jul 2006, 07:42
this is my personal import macro i write sometimes ago.. (read the comment in source)
Code: ;USAGE ;to import items from a dll, use ; ; import <dllRefName>['('<dllString>')'], <importItemName>[':'<importItemStringOrOrdinal>] [,<importItemName>[':'<importItemStringOrOrdinal>]]* ; ;to declare the import table, use ; ; .import ;no new section ; ;or ; ; @import ;new section ; ;or ; ; @import '('<sectionName>')' ;new section with name ; ;NOTE : '.import' MUST BE USE AFTER ALL 'import' ; ;to reference imported item, use the importItemName, e.g ; ; format pe gui 4.0 ; import user32('user32.dll'), MessageBox:'MessageBoxA' ; ; main: ; push 0 mbTitle mbMessage 0x40 ; call [MessageBox] ; ret ; ; mbMessage db 'Hello World from Fasm', 0 ; mbTitle db 'Test', 0 ; ; .import ; ;lastly, can use 'api' (MUST BE USED BEFORE .import) to import function and call them, e.g ; ; api u32('user32.dll')::MessageBox('MessageBoxA') ; ;next call to user32.dll function can just use u32 ; ; api u32::MessageBoxW ; macro importListCreate [@listName*] { match = @listName#created, @listName#created \{ define @listName#created define @listName \} } macro importListAdd @listName, [@item] { common ;display `@listName,13,10 match .item, @item \{ match , @listName#created \\{ match , @listName \\\{ restore @listName define @listName .item define ..do \\\} match =..do .prev, ..do @listName \\\{ restore @listName define @listName .prev, .item \\\} restore ..do \\} \} } macro importListDestroy [@listName*] {match, @listName#created \{restore @listName, @listName#created\}} importListCreate __dllList macro importItems @dllRefName, [@itemSpec] { common ;display `@dllRefName, '-' forward ;display `@itemSpec match .itemRefName:.itemStr, @itemSpec \{ match =.itemRefName\#Exist, .itemRefName\#Exist \\{ define .itemRefName\#Exist importListAdd @dllRefName#itemList, .itemRefName, .itemStr \\} define do \} match =do .itemRefName, do @itemSpec \{ match =.itemRefName\#Exist, .itemRefName\#Exist \\{ define .itemRefName\#Exist importListAdd @dllRefName#itemList, .itemRefName, \`.itemRefName \\} \} restore do ;display 13,10 } macro import @dllSpec, [@itemSpec] { common local dllRefName match .dllRefName(.dllStr), @dllSpec \{ define .dllRefName\#Str .dllStr define dllRefName .dllRefName define do \} match =do .dllRefName, do @dllSpec \{ define .dllRefName\#Str \`.dllRefName define dllRefName .dllRefName \} restore do match .dllRefName, dllRefName \{ match ,.dllRefName\#Exist \\{ restore .dllRefName\#Str importItems .dllRefName, @itemSpec \\} match =.dllRefName\#Exist,.dllRefName\#Exist \\{ define .dllRefName\#Exist importListAdd __dllList, .dllRefName importListCreate .dllRefName\#itemList importItems .dllRefName, @itemSpec \\} \} restore dllRefName } macro @import @nameSpec { match (.name), @nameSpec \{ section .name data readable .import \} match , @nameSpec \{ section '.idata' data readable .import \} restore do } macro .import { match .dllList,__dllList \{buildImportTable .dllList\} importListDestroy __dllList } macro buildImportTable [@dllRefName] { common local ..hasImport, ..dllCount ..dllCount=0 align 4 if ..hasImport data import end if forward if defined @dllRefName#Used dd rva @dllRefName#Oft, 0, 0, rva @dllRefName#Name, rva @dllRefName#Ft ..dllCount=..dllCount+1 end if common if ..dllCount dd 5 dup 0 end if if ..hasImport end data end if ..hasImport = ..dllCount forward match .listName, @dllRefName#itemList \{ match .itemList, .listName \\{buildImportData @dllRefName, .itemList\\}\} if defined @dllRefName#Used @dllRefName#Name db @dllRefName#Str, 0 end if common restore @dllRefName#Str, @dllRefName#Exist importListDestroy @dllRefName#itemList, __dllList } macro buildImportData @dllRefName, [@itemRefName, @itemStr] { common local ..itemCount ..itemCount=0 align 4 @dllRefName#Ft: forward ;display `@itemRefName if used @itemRefName ;display 'foo' if @itemStr eqtype '' local ..label @itemRefName dd rva ..label else @itemRefName dd 0x80000000 or @itemStr end if ..itemCount = ..itemCount+1 end if common local ..temp if $ > @dllRefName#Ft @dllRefName#Used=1 dd 0 ..itemCount = ..itemCount+1 end if @dllRefName#Oft: dd ..itemCount dup 0 repeat ..itemCount load ..temp dword from @dllRefName#Ft+(%-1)*4 store dword ..temp at @dllRefName#Oft+(%-1)*4 end repeat forward if used @itemRefName & @itemStr eqtype '' ..label dw 0 db @itemStr, 0 align 2 end if restore @dllRefName#@itemRefName#Exist } macro api @funcSpec, [@arg] { common match .any, @arg \{ reverse pushd @arg common \} match .dllSpec::.funcSpec, @funcSpec \{ import .dllSpec, .funcSpec match .func:.ignore, .funcSpec \\{ call [.func] define .do \\} match =.do .func, .do .funcSpec \\{call [.func]\\} restore .do define do \} match =do .funcName, do @funcSpec \{call [.funcName]\} restore do } |
|||
14 Jul 2006, 07:42 |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.