flat assembler
Message board for the users of flat assembler.

Index > Windows > Export by ordinals only

Author
Thread Post new topic Reply to topic
nmake



Joined: 13 Sep 2012
Posts: 192
nmake 09 Feb 2013, 15:49
If I want to get rid of the exported function name and only export by ordinal, I use this way:

Code:
export 'name.dll',\
         funcname,0
    


It works, but I am not sure if it is correct, can anyone confirm the correct method of exporting functions in a dll by ordinals only?

If so, how are you supposed to import by ordinals only, other than using loadlibrary and getprocaddress?
Post 09 Feb 2013, 15:49
View user's profile Send private message Reply with quote
l_inc



Joined: 23 Oct 2009
Posts: 881
l_inc 09 Feb 2013, 21:18
nmake
Quote:
It works, but I am not sure if it is correct, can anyone confirm the correct method of exporting functions in a dll by ordinals only?

This is not correct. This way you just export a weird-named function (empty-named in your case).
Here's a macro able to export by ordinals. It also provides control for repeated ordinals. But be advised, that if you specify ordinal values dispersed over a wide numeric range, then you'll get quite a large export table.

Btw. what's the purpose of exporting by ordinal only?
Post 09 Feb 2013, 21:18
View user's profile Send private message Reply with quote
nmake



Joined: 13 Sep 2012
Posts: 192
nmake 09 Feb 2013, 21:58
l_inc wrote:
nmake
Quote:
It works, but I am not sure if it is correct, can anyone confirm the correct method of exporting functions in a dll by ordinals only?

This is not correct. This way you just export a weird-named function (empty-named in your case).
Here's a macro able to export by ordinals. It also provides control for repeated ordinals. But be advised, that if you specify ordinal values dispersed over a wide numeric range, then you'll get quite a large export table.

Btw. what's the purpose of exporting by ordinal only?


If you get addresses of your exported functions directly through getprocaddress then you don't need the function names, it also adds another indirect layer. Function names give off clue to the nature of what a function do, cutting away names give debuggers a harder time guessing what it does. Having names in an important dll is like putting labels on the door of your safe where you keep your gold, a note where it says "Come on in here, steal my gold right away"
Post 09 Feb 2013, 21:58
View user's profile Send private message Reply with quote
l_inc



Joined: 23 Oct 2009
Posts: 881
l_inc 09 Feb 2013, 22:11
nmake
Quote:
If you get addresses of your exported functions directly through getprocaddress

You don't have to import with GetProcAddress in order to import by ordinal. The standard import macro is able to handle ordinals instead of names.
Quote:
Function names give off clue to the nature of what a function do, cutting away names give debuggers a harder time guessing what it does.

I'm pretty sure that debuggers don't try to guess the functionality from function names. Wink
Regarding reverse engineers I'd say, that if someone needs to reverse engineer your dll, hiding exported names is of no effect. Besides, you could use any randomly generated export name. At least you wouldn't have to pay attention on ordinal inconsistencies between the versions of your dll's in this case.
Post 09 Feb 2013, 22:11
View user's profile Send private message Reply with quote
nmake



Joined: 13 Sep 2012
Posts: 192
nmake 09 Feb 2013, 22:18
l_inc wrote:
nmake
You don't have to import with GetProcAddress in order to import by ordinal. The standard import macro is able to handle ordinals instead of names.

That is only true if you know the dll in and out, if you intend to share it, thats not always the case. But I am not talking about multiple ways of importing it, I am only mentioning the standard, default way.
l_inc wrote:

I'm pretty sure that debuggers don't try to guess the functionality from function names. Wink

And you're right, debugger's as the reverse engineer Smile, not the debugger itself.
l_inc wrote:

Regarding reverse engineers I'd say, that if someone needs to reverse engineer your dll, hiding exported names is of no effect.

It has a huge effect, especially if the dll is large, and the reverser have a huge task ahead of him, having a huge list of names makes the difference between alpha and omega.

I think maybe you are confusing normal breakpoints, tracing and general debugging with functionality of the code. You can easily track code, but you cannot easily tell what it does without going deeper into the code, perhaps it has a bitfield and you don't know anything about what each bit does, then having a function name will reveal what it does.

I think maybe you are thinking of breaking protection schemes, like nop'ing out small bits here and there, that's easy without function names, but if you are a serious reverse engineer, going out to change the functionality of a program, then you need more tools at hand, an evergrowing need for more information, more information is always better. Serious reverse engineers doesn't just nop out instructions here and there, they change the entire functionality of a program, even create their own library to add to the program. Smile


Last edited by nmake on 09 Feb 2013, 22:36; edited 3 times in total
Post 09 Feb 2013, 22:18
View user's profile Send private message Reply with quote
HaHaAnonymous



Joined: 02 Dec 2012
Posts: 1178
Location: Unknown
HaHaAnonymous 09 Feb 2013, 22:21
[ Post removed by author. ]


Last edited by HaHaAnonymous on 28 Feb 2015, 21:35; edited 2 times in total
Post 09 Feb 2013, 22:21
View user's profile Send private message Reply with quote
nmake



Joined: 13 Sep 2012
Posts: 192
nmake 09 Feb 2013, 22:23
Removing function names is not a protection method, it is just another daily routine. Those of you who think it is, perhaps you assume badly, it is just routine work and it is effortless to do in other assemblers that I've used, but in fasm I have to get used to the different macros available.

It is very simple math:

Function ordinal = 10 (Reverse engineer spend 30 minutes to figure out what the code is doing)

Function name = SendEncryptedMessage (reverse engineer saves 20 minutes)

Library has got 150 functions and can finish his work in a third of the time.
Post 09 Feb 2013, 22:23
View user's profile Send private message Reply with quote
l_inc



Joined: 23 Oct 2009
Posts: 881
l_inc 09 Feb 2013, 22:51
nmake
Quote:
perhaps it has a bitfield and you don't know anything about what each bit does, then having a function name will reveal what it does

You don't have an exported function for every bit of every bitfield, do you? And that's the point. The percentage of the exported functions is normally very low compared to the total code size.

Quote:
but in fasm I have to get used to the different macros available

Oh, that's quite questionable, because the macro I provided has almost the same interface as the standard macro (just use two commas instead of one to omit the function name and to specify the ordinal). So, I'd say, getting used to the macro is effortless. Getting used to the syntax of the DEF-files is kinda problem.[/i]
Post 09 Feb 2013, 22:51
View user's profile Send private message Reply with quote
nmake



Joined: 13 Sep 2012
Posts: 192
nmake 09 Feb 2013, 22:55
l_inc wrote:
Besides, you could use any randomly generated export name. At least you wouldn't have to pay attention on ordinal inconsistencies between the versions of your dll's in this case.


There is a fine reason why names is an entity in programming, be sure to remind me what purpose your encrypted function names is going to have. Whatever the purpose it is going to have, it is not to identify something, but to obfuscate, which proves my point, that if you don't need them you don't need them, and especially not if you intend to encrypt function names like you imply here. The purpose of a name or a label is to be able to identify something, encrypted names is not usable to anything.
Post 09 Feb 2013, 22:55
View user's profile Send private message Reply with quote
nmake



Joined: 13 Sep 2012
Posts: 192
nmake 09 Feb 2013, 22:59
l_inc wrote:

You don't have an exported function for every bit of every bitfield, do you? And that's the point. The percentage of the exported functions is normally very low compared to the total code size.

It depends on your experience in reverse engineering, I can only talk from my own experience, and I've seen many times that large programs ship with tiny functions, a lot of them, very tiny functions exported.

More information is better to a reverse engineer, always.
l_inc wrote:
Getting used to the syntax of the DEF-files is kinda problem.[/i]

I have used definition files with masm for years and I know them in and out, it's very easy.
Post 09 Feb 2013, 22:59
View user's profile Send private message Reply with quote
l_inc



Joined: 23 Oct 2009
Posts: 881
l_inc 09 Feb 2013, 23:07
nmake
Quote:
Whatever the purpose it is going to have, it is not to identify something, but to obfuscate

You seem to not understand the difference between the exported name and a name used in your source codes. The purpose of the exported name is not identification by a human, but by an importing program.

Ordinals in turn are nothing more than a position in an array. The advantage of exporting by name is therefore to be able to abstract from the array positions. So that you for example do need an array of 1000 elements when exporting just two functions.
Post 09 Feb 2013, 23:07
View user's profile Send private message Reply with quote
nmake



Joined: 13 Sep 2012
Posts: 192
nmake 09 Feb 2013, 23:13
l_inc wrote:
nmake
The purpose of the exported name is not identification by a human, but by an importing program.

The guy who is going to use your library will take advantage of the importing program or loader, but he will have to get familiar with the names before using the library, even though the loader uses the names, it ultimately is the programmer who is dependent on the names. So I strongly disagree with you.
l_inc wrote:

Ordinals in turn are nothing more than a position in an array. The advantage of exporting by name is therefore to be able to abstract from the array positions. So that you for example do need an array of 1000 elements when exporting just two functions.

Well, what ordinals are and are not is not that relevant, it is just a number used to relate to an address, as long as it serves the purpose of replacing names, I think that the definition of what ordinals are is uninteresting. Smile
Post 09 Feb 2013, 23:13
View user's profile Send private message Reply with quote
l_inc



Joined: 23 Oct 2009
Posts: 881
l_inc 09 Feb 2013, 23:31
nmake
Quote:
but he will have to get familiar with the names before using the library, even though the loader uses the names, it ultimately is the programmer who is dependent on the names

The guy will be getting familiar with the names, he will be using in his source codes, not with the names, exported from the dll binary. Just look what (mangled) names are used in C++ static libraries and try to get familiar with _ZNSs7replaceEN9__gnu_cxx17__normal_iteratorIPcSsEES2_PKcS4_ Wink. Or have you tried to import COM-objects? What matters there is a guid. You're not getting familiar with DEBBD32E-1D08-4F6A-8A26-E1B3D768A1E5. You're getting familiar with names, specified in the headers.
Quote:
it is just a number used to relate to an address

It is a number, that has an important collateral impact on your binary. Just try to use the macro I provided to export one function with the ordinal 1 and one function with the ordinal 100000 from a very simple dll.
Quote:
as long as it serves the purpose of replacing names, I think that the definition of what ordinals are is uninteresting

The point is that it serves worse, than a function name, even an obfuscated one.
Post 09 Feb 2013, 23:31
View user's profile Send private message Reply with quote
nmake



Joined: 13 Sep 2012
Posts: 192
nmake 10 Feb 2013, 01:18
The added bits of information is not mandatory, but usually you can read the calling convention at the beginning followed by the name and size of the parameters. GUID is not mandatory and the names are still relevant to the programmer, the programmer doesn't deal with GUID's, the idea of that is insane in itself Smile
Post 10 Feb 2013, 01:18
View user's profile Send private message Reply with quote
l_inc



Joined: 23 Oct 2009
Posts: 881
l_inc 10 Feb 2013, 15:25
nmake
Quote:
The added bits of information is not mandatory

To my knowledge those are mandatory. This is the way the C++ cross-unit type checking works. If you don't have mangled names, then it's not C++.
Quote:
but usually you can read the calling convention at the beginning followed by the name and size of the parameters

You're confusing C++ name mangling with simple C name decoration.
Quote:
GUID is not mandatory and the names are still relevant to the programmer

GUID is mandatory unless you are creating an object of a well-known predetermined type. For any third-party objects registered in the registry you will need it's class identifier (and interface identifier), i.e. a GUID, to pass into the CoCreateInstance.
Quote:
the programmer doesn't deal with GUID's, the idea of that is insane in itself

See the usecom.asm example from the fasm package.
Post 10 Feb 2013, 15:25
View user's profile Send private message Reply with quote
nmake



Joined: 13 Sep 2012
Posts: 192
nmake 10 Feb 2013, 17:22
The whole point is that the programmer doesn't use GUID to refer to function names. It's just an underlying layer, it would be too much to remember 128 bit numbers like you seem to suggest. Name convention stays the same despite the underlying GUID system so I have to disagree with you again. Smile

And I might also add that despite the GUID system uses the exported names, doesn't mean function names were designed for GUID, it's just that GUID takes advantage of names, in fact it's the other way around, names were designed for identification by the programmer. Things evolved, but they didn't evolve for you to redefine the original purpose.
Post 10 Feb 2013, 17:22
View user's profile Send private message Reply with quote
l_inc



Joined: 23 Oct 2009
Posts: 881
l_inc 10 Feb 2013, 18:39
nmake
Quote:
The whole point is that the programmer doesn't use GUID to refer to function names.

The fact is that this is also my point. Smile What is specified as an exported name in your dll binary does not necessarily needs to be the function name, that you use in your source codes to define or call the function. This makes the exported name to be nothing more, than such "an underlying layer". And therefore export by ordinal only or import by ordinal does not make much sense for your case.
Post 10 Feb 2013, 18:39
View user's profile Send private message Reply with quote
nmake



Joined: 13 Sep 2012
Posts: 192
nmake 10 Feb 2013, 21:26
I'd prefer to loop from ecx=1 to ecx=10 than looping from StrToInt(1)..StrToInt(10) Smile

It still makes sense to me.
Post 10 Feb 2013, 21:26
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.