@会网络的老鼠

涂飞平的博客空间

完成一个极小模式汇编编译器

9 年前 0

写一个极小模式编译器的想法其实一直都有(2005年4月份写了一个虚拟机,当时自己组织bytecode,当时就想写一个编译器,后来因为没有时间只好作罢,只写了一个解析机和简单的字节码编译器),一来有时候有这种需要,二来想通过写这个东西来多学习了解一些东西,趁这段时间没有什么事情,所以就开始试着实现这个梦想了^_^
经过2天的测试,可以运行,但还没有时间做全面测试,未来几天会进一步完善代码。可以到我的空间下载这个Tiny ASM Compiler(sundytu.ys168.com)
下面是我写的一个简单的帮助文件,放在这里,充充门面^_^

Tiny ASM Compiler


Tac readme file.


Write by
Sundy TU 2008-1-24


什么是极小模式的应用程序?


极小模式的应用程序就是为了达到一个简单的功能,以极少的代码和最小的代价生成的一个应用程序。如果在网上搜索关键字-“打造微型PE文件”可以查找到不少的条目,但绝大多数都是涉及到使用手工方式构造的,而且大小范围大致都是在512-1024字节之间的。而tac是一个可以根据输入的源代码生成极小模式应用程序的编译器。大部分生成的PE文件大小都在1k至数k之间,如果你只要完成简单的功能,而又不愿意使用其他的开发工具(诸如VC ,Delphi,VB)开发臃肿的程序,试试tac吧!


什么人可以使用tac编译程序?


使用这个编译器,你必须懂得如何使用汇编语言,虽然这个编译器可编译的语言只是汇编语言的一个子集,要求不多,但你至少应该知道一般的指令使用方法和tac需要你注意的地方(见下面介绍),由于tac生成的程序很小,你也可以作为反汇编研究或者作为研究PE文件的范例,当然,如果你技术可以的话,甚至可以使用tac编译出病毒程序(很小的病毒,便于隐藏和下载,范例程序中有一个下载程序的示例),当然,这个与tac的作者无关^_^
本文件说明:这个文件可以告诉你如何使用TAC(Tiny ASM Compiler)编译器编译极小模式的应用程序。


注意:TAC只编译32位指令,由于32位模式下段寄存器都没有实际作用(FS除外,其他的作为选择子其实也没有什么实际作用),所以TAC编译器不支持段寄存器操作。TAC也不支持16位/8位的寄存器,如AX/AL/AH等寄存器,它只支持EAX,ECX,EDX,EBX,EBP,ESP,ESI,EDI八个通用寄存器。TAC支持的寻址模式有:1、立即数寻址(mov eax,1) 2、直接寻址(mov eax,[1234]) 3、间接寻址(mov eax,[edx]) 4、基址 变址寻址(mov eax,[eax 1234]) 5、寄存器寻址(mov eax,edx),为了编译器的简单,暂时不支持基址 变址 比例等复杂的寻址方式。


支持的指令有(按字母排序):

add,and,clc,cld,cmc,cmp,cmpsb,cmpsw,cmpsd,dec,div,idiv,imul,
inc,int,lds,les,lodsb,lodsw,lodsd,lea,mov,movsb,movsw,movsd,
mul,nop,not,or,pop,popa,popad,push,pusha,pushad,rcl,rcr,ret,
rol,ror,sal,sar,shl,shr,scasb,scasw,scasd,stc,std,stosb,stosw,
stosd,sub,test,xchg,xor,call,jmp,loop,loopz,loope,loopnz,
loopne,rep,repe,repz,repne,repnz,jcxz,jcxe,jecxz,jecxe,jcc,ja,
jnbe,jae,jnc,jnb,jb,jnae,jbe,jna,jc,jnae,je,jz,jg,jnle,jge,
jnl,jl,jnge,jle,jng,jne,jnz,jno,jnp,jpo,jns,jna,jo,jp,jpe,
js,jnz,jne,xlat
且这些指令必须都是32位形式的。
代码的组织形式:
import  dllname   function-name,function-name2  //导入函数声明 
.data //数据声明
Var-nam var-type var-data
.code //代码区域
proc proc-name //子过程定义
move eax,eax
endproc
mov eax,eax //instruction
Start: //注释形式,start是每个程序必须有的标签,表示程序的开始
mov eax,eax
nop
.end
代码分为1、导入函数声明(Win2000要求PE文件必须有导入函数) 2、数据声明,暂时只支持DD(DWORD)类型和DB(String)类型,对于byte类型可以使用DD类型,毕竟指令只支持32位的,不能定义非初始化的数据,如果需要定义一个变量,你可以定义为dd,不过应该赋值为0,转化为初始化数据就可以使用了,因为.data区域的数据是可以读写的 3、代码区域,在代码内部可以再定义子过程(使用标签proc……endproc),代码中必须有一个标签是Start,它表示程序的开始地址,所有的内部标签都是采用“标签名:”形式定义的 4、文件末尾必须有.end表示汇编结束标志。


注意:导入函数最多可以导入的DLL数量是126个,每个DLL可以导入的函数数量也是126,因为只是一个Tiny编译器,为了使得编译方便且文件足够的小,故有此限制。


TAC只支持单文件编译,不支持MACRO(宏),Include和Offset/Addr等伪指令(不支持伪指令)。如果要获取某个标号的地址,可以使用lea eax,[标号]或者lea eax,标号来操作。


下面是一个实际例子(作用:下载一个gif图片并显示它):


.import urlmon.dll URLDownloadToFileA
.import shell32.dll ShellExecuteA
.import kernel32.dll ExitProcess
.data
path db http://www.vckbase.com/image/mlogo.gif
local db "D:TestDown.gif"
tip db "Tip"
caption db "Download successful."
open db "open"
SWWINDOW dd 0
.code
proc downloadbmp
push 0
push 0
lea eax,local //对于获取标签地址,都只能采用先使用lea指令获取地址,然后再将获取的地址做其他处理
push eax
lea eax,path
push eax
push 0
call URLDownloadToFileA
push SWWINDOW
push 0
push 0
lea eax,local
push eax
lea eax,open
push eax
push 0
call ShellExecuteA
push 0
call ExitProcess
start:
call downloadbmp
nop
endproc
.end
编译方法:
tac是一个控制台程序(没有界面),你可以通过使用tac外加参数来控制编译器的操作。
参数表:
Tac pe sourcefilepath targetfilename [param]
Pe选项表示要生成pe文件格式
Sourcefilepath选项是源文件地址和名称
Targetfilename选项是生成的目标文件的地址名称
Param是可选选项,有cui和gui两项,分别表示生成字符界面和gui界面程序
下面是一个编译批处理文件内容(ac.bat):

ac pe src3.txt 测试.exe gui


由于编译器没有做任何宏处理,故编译出来的代码将严格遵循输入的代码,所以在PE文件中一般都应该有这个导入函数:.import kernel32.dll ExitProcess,在代码需要退出的时候应该call ExitProcess,否则进程会形成僵死进程。导入函数名称是大小写敏感的(主要是Windows载入程序有这个要求^_^)


现在的编译器很简单,测试大部分指令,但还没有经过严谨的测试,所以肯定会出现这样或者那样的问题,如果你发现了问题,请告诉我,便于我更好的完善这个编译器,我的联系方式:email:tufeiping@hotmail.com website:sundytu.blogcn.com

版本历史:
2008-1-12开始写一些辅助例程和大致框架代码


2008-1-24完成第一版本的程序,可以生成1k大小以内的PE文件


2008-1-25完成此帮助文件


2008-1-26增加了.bss,可以进一步减小PE的体积,并有限支持16位寄存器,增加了dw数据类型支持
2008-1-27改善了指令支持,对于所有的列出的指令提供了不错的支持,写了一个小的IDE支持tac,但功能还不够。
2008-1-31增加了数组常/变量的声明,例如 arraydata dw dup(100) ?变量声明方式 arraydata dw dup(50) 123常量声明方法。常量的声明是占用PE文件体积的,变量的声明不占用PE文件体积。

编写评论