Consider this small C program:
/****************/
/* MessageBox.c */
/****************/
#include <windows.h>
void Entry(void);
void Entry(void)
{
MessageBox(NULL, "PellesC", "Hello!", MB_OK);
ExitProcess(0);
}
Use PellesC to create it with something like:
@echo off
rem ***************
rem * PellesC.bat *
rem ***************
set PATH=\PellesC\Bin
set INCLUDE=\PellesC\Include;\PellesC\Include\Win
set LIB=\PellesC\Lib\Win
pocc -Tx86-coff -Gz -Ze MessageBox.c
polink -entry:Entry@0 -nodefaultlib -subsystem:windows MessageBox.obj Kernel32.lib User32.lib
del MessageBox.obj
pause
Once it is created you will have an executable named MessageBox.exe.
Some notes about the produced file:
It has a size of 2,048 bytes.
It has three sections.
It has .text, .data, and .rdata sections.
The strings were placed in the .rdata section.
The import table was placed in the .data section.
Then consider this MASM program:
;******************
;* MessageBox.asm *
;******************
.386
.model flat, stdcall
option casemap:none
public start
ExitProcess proto :dword
MessageBoxA proto :dword, :dword, :dword, :dword
MessageBox equ <MessageBoxA>
.data
strCaption db 'Masm', 0
strText db 'Hello!', 0
.code
start:
invoke MessageBox, 0, offset strCaption, offset strText, 0
invoke ExitProcess, 0
end start
A small batch file to create it:
@echo off
rem ******************
rem * MessageBox.bat *
rem ******************
set Path=\Masm32\Bin
set Lib=\Masm32\Lib
ml /c /coff MessageBox.asm
link /subsystem:windows /entry:start MessageBox.obj kernel32.lib user32.lib
del MessageBox.obj
pause
It has a size of 2,560 bytes.
It has three sections.
It has .text, .data, and .rdata sections.
The strings were placed in the .data section.
The import table was placed in the .rdata section.
Of course there are things that could be done to decrease size:
In the C program, one could have forced the strings
to the .data section with something like:
char strCaption[] = "PellesC", strText[] = "Hello!";
MessageBox(NULL, strCaption, strText, MB_OK);
In the Asm program, you might use .const instead of .data.
But, the attempt here is to get two programs that are "similar"
and contain the same number of sections.
The C program is 2,048 bytes, yet the Asm program is 2,560.
They both have three sections. What's the difference?
Since we all know that our section size here is 512 byes,
the difference is in the header size. PellesC used a
header of 512 bytes, the Asm version used 1024 bytes.
In this case, the larger size resulted from the "Rich Signature"
that MS link.exe placed in the header. Basically this "watermark"
can identify the tools that were used to build the EXE. The "compids"
can also provide information about libraries used. Another
fine feature of MS products (sarcasm).
To learn more, go here:
http://trendystephen.blogspot.com/2008/01/rich-header.html
and here:
http://ntcore.com/files/richsign.htm
One solution to this annoying little problem is to patch the linker.
If you do this, you're on your own (and don't forget to make a backup).
Open \masm32\bin\link.exe (version 5.12) in a hex editor.
You need to NOP two bytes.
8B8D E0010000 mov ecx, dword ptr [ebp+1E0]
894424 10 mov dword ptr [esp+10], eax
03C8 add ecx, eax <-- NOP this instruction
898D E4010000 mov dword ptr [ebp+1E4], ecx
Go To Offset 4511B:
-- --
00045110: ff 8b 8d e0 01 00 00 89 44 24 10 03 c8 89 8d e4
Change the 03 C8 to NOPs 90 90
00045110: ff 8b 8d e0 01 00 00 89 44 24 10 90 90 89 8d e4
The other solution is to write a program to do the job for you.
Attached is RichSignature.zip. Just run RichRemove.exe as a
post link step.
It doesn't always reduce the program size. It does reduce it
when the crap that was added crosses the next boundry of
File Alignment. But, it always removes the watermark.
I'm a bit new to this PE format stuff. So don't run it against
something important.
If you improve the code, how about posting it back! I'm sure that
many bases weren't covered in the code. Something to play with.
Hope this might be worth something to someone.
Mark
1024 bytes:
include \masm32\include\masm32rt.inc
.code
AppName db "Masm32:", 0
HelloW db "Hello World", 0
start: MsgBox 0, addr HelloW, addr AppName, MB_OK
exit
end start
OPT_Linker polink
OPT_DebugL /MERGE:.data=.rdata /MERGE:.rdata=.text ; linker options for ultra short executables
The other question is what heuristic AV scanners have to say on that ;-)
i wouldn't be patching the linker without a good reason :bg
but, if you use polink, it will probably be 2 Kb
Quote from: dedndave on March 06, 2010, 08:35:30 PM
but, if you use polink, it will probably be 2 Kb
1k with /MERGE:.data=.rdata /MERGE:.rdata=.text, as shown above
RotateRight,
It is very old stuff... :wink
You can look back at 2003 when I "invented" the Rich structure and NOP, NOP (90h, 90h) (see: http://www.asmcommunity.net/board/index.php?topic=10554.120) just to answer TheSvin's question about it.
See S.T.A.S.'s "Lingo, thanks a lot!" and CodeTester's "Lingo , thank you very much for your interesting post about the encrypted data in the DOS stub." here: http://www.asmcommunity.net/board/index.php?topic=14699.msg113971#msg113971
Quote from: lingo on March 07, 2010, 12:32:26 PM
It is very old stuff...
Like 1998, when DanS (Dan Spalding) added in the Delayed Import stuff as well.
-Clive