文章作者:anskya
代码:
[声明]ByAnskya
初学翻译,由于英语基础和写作风格的差异,可能导致译文与原文的一些差异
如有不明请阅读原文,谢谢大家支持....
为了更适合大家阅读和理解文章内容这里将使用一些比较容易理解的语句
请大家不要责怪小弟翻译水平不好.(原文直接翻译会令人非常费解)
由于本人能力有限,翻译过程中难免会出现错误,请大家指正,
写希望大家多多交流,谢谢各位支持和看完此文,转载请保留版权
[ByAnskya]Email:Anskya@Gmail.comQQ:115447
//-------------------------------------------------
编译迷你Win32可执行文件(使用C代码)
作者:DoxtorL.,西元2004年
如今人们使用各类加壳软件程序压缩应用程序使自己的程序更短小,
使得大家都忽略(原文:是否因为懒惰?)了如何自己编译一个小巧的二进制文件,
希望下面所讲述的可以给你一些思路..
(个人理解是这个意思~不明的地方看原文~这里只是依照个人思维翻译的)
摘要:
简介.
第1讲.不使用代码,定位代码入口点和C语言连接时间库(就是*.lib)
第2讲.融合PE节
第3讲.使用Dosstub(DOS插桩柱)来存储初始化数据(可以解释成常量!)
第X讲.再进一步......等等....
源代码:test.c,test2.c
介绍:
编译迷你的应用程序是建立在一个好的连接器基础上的.
这里我使用的是Pelles-c的连接库
(译者注:Pelles-c,类似LCC的一种C语言编译器,其实就是LCC源代码修改的)
Pelles-c是一款免费很不错的编译器(只支持C语言)Polink(指的是连接器)
是模拟科隆M$VC的连接器的.
我使用一个"HelloWorld"程序(test.c)来示范编译一个迷你的应用程序.
(原文意思是~我应该用次来优化一个二进制文件...不理解他是什么意思)
*****第0讲:默认编译
使用命令:
cc.exetest.c
polink.exec:\progra~1\pellesc\lib\crt.libc:\progra~1\pellesc\->
lib\win\kernel32.libtest.obj
result:test.exe,size=27648bytes
这个体积有点大了,但是程序只使用了Kernel32.dll中的函数
*****第1讲:
不使用代码,重定位代码入口点和C语言连接时间库(就是*.lib),
连接器使用一个常规的入口点,代码功能:读取和解析附加参数.
我们的例子不需要上面的特征(命令),为了优化我们的代码我们决定去除这些东西
.
连接器有个参数:
/ENTRY:
(/ENTRY:后面跟程序入口函数--一般我们的程序是main开始的)
symbol是你的程序main函数的入口点(译者注:当然你也可以设置成别的函数例如:
/ENTRY:MyMain)
如果我们需要使用一个C连接库可以使用:
/NODEFAULTLIB
编译命令:
cc.exetest.c
polink.exe/NODEFAULTLIB/ENTRY:main
c:\progra~1\pellesc\lib\win\msvcrt.libtest.obj
result:test.exe,size=2560bytes
*****第2讲:融合PE节
(译者注:许多加壳软件加壳后程序的节明显比原来小了.这里所说的就是这个意思
)
我们的test.exe程序编译后拥有2个PE节:.text,.rdata,.data
我们可以融合三个节成为一个节
连接器设置:/MERGE:=
(原文:thisoptioncanbeusedseveraltimes!,感觉无意义就没有翻译)
编译命令:
cc.exetest.c
polink.exe/MERGE:.rdata=.text/MERGE:.data=.text/NODEFAULTLIB
/ENTRY:main->
c:\progra~1\pellesc\lib\win\msvcrt.libtest.obj
result:test.exe,size=1536bytes
*****第3讲:使用Dosstub(DOS插桩柱)来存储初始化数据
DOSStub头部是PE程序为了兼容msdos系统所作的,如果你的程序的程序
在msdos环境下运行,会显示一个"ThisprogramcannotberuninDOSmode"
的警告信息然后退出.(译者注:就和printf打印这条信息一个结果~不过他使用的
是int21中断)
他可以作一些你需要让程序在dos下作的事情(那是你自己的事情这里就不细说了)
dosstub尺寸是512的倍数,最小的可能性也是512字节,如果我们去除警告信息dos
stub
只有160字节,剩下的空间可以用来存储我们的初始化数据(译者注:许多DIYPE的
牛人都作过小于
512字节的dosstub..似乎原作者认为dosstub必须是512字节不然就会发生什么
事情..:P)
我们必须改变少量的C代码,
我们需要将数据分成两个部分,一个部分保存在dos
stub中,剩下的部分保存在.text段中.
Polink连接器可以设置我们需要使用的dosstub.这里我们用一个免费的汇编语言
编译器FASM来作
(译者注:B人很喜欢的一个编译器,开源,有大量的宏指令可以使用,由于是低级编
译器可以按照自己的设想编译PE结构)
编译器设置参数:/STUB:,这里设置我们需要的dosstub的二进
制文件(这么说话好别扭~:D)
编译命令:
fasmstub.asmstub.bin
cc.exetestb.c
polink.exe/STUB:stub.bin/MERGE:.rdata=.text/MERGE:.data=.text
/NODEFAULTLIB/ENTRY:main->
c:\progra~1\pellesc\lib\win\msvcrt.libtestb.obj
*****第X讲:再进一步
(译者注:dosstub中)可以保存你需要导入的DLL的函数名和~"ByName"等等字符
串信息
(似乎好多壳都这样作了~比如(Win)Upack,FSG等等壳),一般使用导入序数不是一
个好主意,
因为操作系统的差别~(译者注:比如Win2k,WinXp,Win9x下的函数未必就是一个序
号.大家需要注意这里)
总之..一些DLL,如wsock32.dll,你完全没有必要在Windows下使用序数....
对导入表使用序数,你需要使用一些特别的方法导入连接库....
一个不需要使用代码的方法,在你连接程序的创建导入表列表的方法.
polib.exe这个工具可以创建你连接库的导入表保存成一个.def的文件
这里是一个演示的文件:
*****exampleofa.deffile
LIBRARYWSOCK32
EXPORTS
accept@1
bind@2
closesocket@3
connect@4
htons@9
listen@13
recv@16
send@19
socket@23
gethostbyname@52
WSAAsyncSelect@101
WSACleanup@116
WSAStartup@115
*****endoffile
.def文件保存了我们需要导入的wsock32.dll的函数,不是全部只有我们需要的
@XXX
symbols是设置我们需要使用的函数名称-.xxx是我们需要导入的函数序数
polib.exe同时会创建一个.lib的文件
改变PE字节的一种BT方法(译者注释:原文翻译是这样:获取文件数据的一种BT方法
.)
,一个PE文件必须是512的倍数(老毛病又犯了.)
和一些小于1024字节的程序还是可以和Win32相兼容的.
(译者注:这里说的是文件对齐~512字节,一开始我也没看懂以后看了下面的代码
才明白)
这个方法是:调整PE文件的对齐字节(设置成512的倍数--当然也可以是使用512)
这样调整后,文件的第一个节的虚拟地址偏移+大小就是文件的大小(接近于1000h
的倍数.也可以是1024)
(译者注:剩下的部分原作者都没有写~也许是我翻译的有问题,反正就没了~呵呵
不知道是什么意思)
以下为源代码
/*****test.c*/
#include
#definePOEM"\
Itmightbelonelier\r\n\
WithouttheLoneliness--\r\n\
I'msoaccustomedtomyFate--\r\n\
PerhapstheOther--Peace--\r\n\r\n\
WouldinterrupttheDark--\r\n\
AndcrowdthelittleRoom--\r\n\
Tooscant--byCubits--tocontain\r\n\
TheSacrament--ofHim--\r\n\r\n\
IamnotusedtoHope--\r\n\
Itmightintrudeupon--\r\n\
Itssweetparade--blasphemetheplace--\r\n\
OrdainedtoSuffering--\r\n\r\n\
Itmightbeeasier\r\n\
Tofail--withLandinSight--\r\n\
Thangain--MyBluePeninsula--\r\n\
Toperish--ofDelight--\r\n\r\n\
(EmilyDickinson,1830-1886)\r\n"
voidmain()
{
printf(POEM);
}
/*****Endofsourcecode*/
/*****test2.c*/
#include
#definePTR_POEM10x400040
#definePOEM2"\
littleRoom--\r\n\
Tooscant--byCubits--tocontain\r\n\
TheSacrament--ofHim--\r\n\
IamnotusedtoHope--\r\n\
Itmightintrudeupon--\r\n\
Itssweetparade--blasphemetheplace--\r\n\
OrdainedtoSuffering--\r\n\r\n\
Itmightbeeasier\r\n\
Tofail--withLandinSight--\r\n\
Thangain--MyBluePeninsula--\r\n\
Toperish--ofDelight--\r\n\r\n\
(EmilyDickinson,1830-1886)\r\n"
voidmain()
{
printf("%s%s",PTR_POEM1,POEM2);
}
/*****Endofsourcecode*/
作者原文没有帖FASM部分的代码我这里补上
下载最新的FASM版本然后直接编译就好了,会生成一个stub.bin文件
请自行修改成stub.exe然后在按照上面所说的文章进行编译就可以了
/*****stub.asm*/
DOS_Header:
.e_magicdw"MZ";IMAGE_DOS_SIGNATURE
.e_cblpdw0x0080
.e_cpdw0x0001
.e_crlcdw0x0000
.e_cparhdrdw0x0004
.e_minallocdw0x0010
.e_maxallocdw0xFFFF
.e_ssdw0x0000
.e_spdw0x0140
.e_csumdw0x0000
.e_ipdw0x0000
.e_csdw0x0000
.e_lfarlcdw0x0040
.e_ovnodw0x0000
.e_resrw4
.e_oemiddw0x0000
.e_oeminfodw0x0000
.e_res2rw10
.e_lfanewddPE_header;PEheaderOffset
DOS_Stub:
org$+DOS_Stub
POEM1db"Itmightbelonelier",0dh,0ah
db"WithouttheLoneliness--",0dh,0ah
db"I'msoaccustomedtomyFate--",0dh,0ah
db"PerhapstheOther--Peace--",0dh,0ah,0dh,0ah
db"WouldinterrupttheDark--",0dh,0ah
db"Andcrowdthe",0
rb160-(DOS_Stub-$)
PE_header:
/*****Endofsourcecode*/
由于本人能力有限,翻译过程中难免会出现错误,请大家指正,
写希望大家多多交流,谢谢各位支持和看完此文,转载请保留版权
[ByAnskya]Email:Anskya@Gmail.comQQ:115447