小弟菜菜~这篇是以前写的东西一直没有发出来献丑。。
新年到了余下的时间也不多了就发出来大家一起斜视一下好了
//Start~~~
《Delphi实现无导入表程序》
初学编程,请勿奸笑:P
首先感谢,一些认识不认识的前辈高人的资料.谢谢~

前提假设您已经有了一定的PE Virus的知识.
好了~先简单的说说无导入表程序的几点基本的构成
1.GetkernelBase(获取kernel32.dll的基址)
由于我们是无导入表的程序所以,所有API函数都是依靠内存搜索完成的,
想必大家已经知道EXE载入到内存中ESP保存ExitThread函数地址
ExitThread函数是在kernel32.dll 模块中的,所以证明EXE载入的时候就已经加载
了kernel32.dll模块,于是我们的工作就是确定kernel32.dll的基址。

这里我使用"PEB获取地址kernel32.dll基址"的方法(简单嘛。。Delphi调试这种程序很麻烦的~所以使用这个。。)

代码:
asm   mov eax,fs:$30   mov eax,[eax + $0c]   mov esi,[eax + $1c]   lodsd   mov eax,[eax+$08]                //这个时候eax中保存的就是k32的基址了 end;


基址获取到了剩下的就是需要确定我们需要的两个重要的函数
"GetProcAddress"和"LoadLibraryA"两个函数~有了这两个函数我们就可以
获取到我们需要的任何函数了..

2.自构建"GetProcAddress"函数
上面我们已经获取到k32的基址了~但是问题是我们还需要一些其他函数来完成我们程序
的功能,首先我们回顾一下~前辈们写的API搜索函数,为了减少程序体积和保护程序自身
他们基本上都是使用hash值来搜索模块的导入表的,这样我们就可以自己构建一个API搜索
函数了。直接贴代码好了~其实Delphi版本的API搜索函数许多前辈都写过
Aming,老王,liumazi等等~

代码:
FUNCTION GetProcAddress(Module:Cardinal;ProcessCRC:DWORD) : Pointer; VAR   ExportName           : pChar;   Address              : Cardinal;   J                    : Cardinal;   ImageDosHeader       : PImageDosHeader;   ImageNTHeaders       : PImageNTHeaders;   ImageExportDirectory : PImageExportDirectory; BEGIN   ImageDosHeader:=Pointer(Module);   ImageNTHeaders:=Pointer(Module+ImageDosHeader._lfanew);   ImageExportDirectory:=Pointer(ImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress+Module);   J:=0;   Address:=0;   REPEAT     ExportName:=Pointer(Cardinal(Pointer(Cardinal(ImageExportDirectory.AddressOfNames)+Module+J*4)^)+Module);     IF CalculateCRC32(ExportName^,StrLen(ExportName))=ProcessCRC THEN       Address:=Cardinal(Pointer(Word(Pointer(J SHL 1+Cardinal(                ImageExportDirectory.AddressOfNameOrdinals)+Module)^) AND                $0000FFFF SHL 2+Cardinal(ImageExportDirectory.AddressOfFunctions)                +Module)^)+Module;     Inc(J);   UNTIL (Address<>0)OR(J=ImageExportDirectory.NumberOfNames);   Result:=Pointer(Address); END;


好了~此函数就可以帮我们,循环对比ProcessCRC参数中给出的API的hash值
然后发挥这个函数的地址,我这里使用的是Crc32算法~
上面的PE的数据结构可以从Windows中Copy出来

代码:
PROCEDURE BuildCRC32Table; ASSEMBLER; ASM     mov       ebx, 0EDB88320h     lea       edi, crc32tab     xor       ecx, ecx   @loc1:     mov       eax, ecx     mov       edx, 8   @loc2:     test eax, 1     jz  @loc3     shr       eax, 1     xor       eax, ebx     jmp       @loc4   @loc3:     shr       eax, 1   @loc4:     dec       edx     jnz       @loc2     stosd     inc       ecx     cmp       ecx, 256     jb  @loc1 END; FUNCTION CalculateCRC32(VAR Buffer;CONST Size:DWORD) : DWORD; ASSEMBLER; ASM     push esi     push edi     push ebx     mov edi,edx     mov esi,eax     xor ebx,ebx     mov eax,$ffffffff     mov ecx,edi     shr ecx,2     jecxz @Rest   @Loop:     mov edx,[esi]     mov bl,al     xor bl,dl     shr eax,8     xor eax,dword ptr [CRC32tab+ebx*4]     mov bl,al     xor bl,dh     shr eax,8     xor eax,dword ptr [CRC32tab+ebx*4]     shr edx,16     mov bl,al     xor bl,dl     shr eax,8     xor eax,dword ptr [CRC32tab+ebx*4]     mov bl,al     xor bl,dh     shr eax,8     xor eax,dword ptr [CRC32tab+ebx*4]     add esi,4     loop @Loop   @Rest:     mov ecx,edi     and ecx,3     jecxz @End   @Loop_Rest:     mov bl,al     xor bl,[esi]     shr eax,8     inc esi     xor eax,dword ptr [CRC32tab+ebx*4]     loop @Loop_Rest @End:     xor eax,$ffffffff     pop ebx     pop edi     pop esi END;


这个是计算一个数据的Crc32数值--返回是10进制的~可以自己改变成16进制

好了现在我们已经有了GetProcAddress函数了~好像还少一个??
前面我们提到过需要两个函数~GetProcAddress有了·k32的基址也有了
这样我们就可以搜索出LoadLibraryA的地址....
好了完成前面的代码

代码:
FUNCTION MyLoadLibraryA:Pointer; const   MyLoadLibraryA=$3FC1BD8D;//LoadLibraryA的Crc32数值 asm   mov eax,fs:$30   mov eax,[eax + $0c]   mov esi,[eax + $1c]   lodsd   mov eax,[eax+$08]                //此时eax中就保存了k32的基址   mov edx,MyLoadLibraryA        //压入LoadLibraryA的Hash   call GetProcAddress                //开始获取LoadLibraryA的地址 end;



好了现在我们两个函数都有了~现在我们的任务已经完成一半了!
(为什么是一半??因为Delphi非等同于VC和XXXASM,他不能够自己构建PE结构)
准确的说~即使你写一个只有一条begin end.的程序~编译器编译的时候还是会连接N多
的API函数~进来....
为了完成任务,我们这里就使用了Nico Bendlin前辈的miniEXE的模板...
自己打造了一个无导入表的程序...
这里需要我们自己编译system.pas和SysInit.pas单元

代码:
//SysInit.pas单元代码 unit SysInit; interface var   TlsIndex: LongWord; implementation end.


System.pas单元代码

代码:
unit System; interface type   DWORD=LongWord;   PLongWord= ^LongWord;   PWord= ^Word;   TGUID = record     D1: LongWord;     D2: Word;     D3: Word;     D4: array[0..7] of Byte;   end; const   Kernel32 = 'kernel32.dll' var   ExitCode: LongWord;   HKernel32: LongWord; procedure _InitExe; procedure _HandleFinally; procedure _halt0; PROCEDURE BuildCRC32Table; //procedure ExitProcess(uExitCode: LongWord); stdcall; FUNCTION  CalculateCRC32(VAR Buffer;CONST Size:DWORD) : DWORD; FUNCTION GetProcAddress(Module:Cardinal;ProcessCRC:DWORD) : Pointer; FUNCTION MyLoadLibraryA:Pointer; implementation CONST   IMAGE_DIRECTORY_ENTRY_EXPORT     = 0;   SIZE_OF_80387_REGISTERS          = 80;   IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;   MAX_API_STRING_LENGTH            = 150;   IMAGE_DOS_SIGNATURE              = $5A4D;   IMAGE_NT_SIGNATURE               = $00004550;   MIN_KERNEL_SEARCH_BASE           = $70000000; TYPE   PImageDosHeader               =^TImageDosHeader;   TImageDosHeader               = PACKED RECORD     e_magic                     : WORD;     e_cblp                      : WORD;     e_cp                        : WORD;     e_crlc                      : WORD;     e_cparhdr                   : WORD;     e_minalloc                  : WORD;     e_maxalloc                  : WORD;     e_ss                        : WORD;     e_sp                        : WORD;     e_csum                      : WORD;     e_ip                        : WORD;     e_cs                        : WORD;     e_lfarlc                    : WORD;     e_ovno                      : WORD;     e_res                       : ARRAY [0..3] OF WORD;     e_oemid                     : WORD;     e_oeminfo                   : WORD;     e_res2                      : ARRAY [0..9] OF WORD;     _lfanew                     : LongInt;   END;   PImageFileHeader              =^TImageFileHeader;   TImageFileHeader              = PACKED RECORD     Machine                     : WORD;     NumberOfSections            : WORD;     TimeDateStamp               : LongWord;     PointerToSymbolTable        : LongWord;     NumberOfSymbols             : LongWord;     SizeOfOptionalHeader        : WORD;     Characteristics             : WORD;   END;   PImageDataDirectory           =^TImageDataDirectory;   TImageDataDirectory           = RECORD     VirtualAddress              : LongWord;     Size                        : LongWord;   END;   PImageOptionalHeader          =^TImageOptionalHeader;   TImageOptionalHeader          = PACKED RECORD     Magic                       : WORD;     MajorLinkerVersion          : Byte;     MinorLinkerVersion          : Byte;     SizeOfCode                  : LongWord;     SizeOfInitializedData       : LongWord;     SizeOfUninitializedData     : LongWord;     AddressOfEntryPoint         : LongWord;     BaseOfCode                  : LongWord;     BaseOfData                  : LongWord;     ImageBase                   : LongWord;     SectionAlignment            : LongWord;     FileAlignment               : LongWord;     MajorOperatingSystemVersion : WORD;     MinorOperatingSystemVersion : WORD;     MajorImageVersion           : WORD;     MinorImageVersion           : WORD;     MajorSubsystemVersion       : WORD;     MinorSubsystemVersion       : WORD;     Win32VersionValue           : LongWord;     SizeOfImage                 : LongWord;     SizeOfHeaders               : LongWord;     CheckSum                    : LongWord;     Subsystem                   : WORD;     DllCharacteristics          : WORD;     SizeOfStackReserve          : LongWord;     SizeOfStackCommit           : LongWord;     SizeOfHeapReserve           : LongWord;     SizeOfHeapCommit            : LongWord;     LoaderFlags                 : LongWord;     NumberOfRvaAndSizes         : LongWord;     DataDirectory               : PACKED ARRAY[0..IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1] OF TImageDataDirectory;   END;   PImageNtHeaders               =^TImageNtHeaders;   TImageNtHeaders               = PACKED RECORD     Signature                   : LongWord;     FileHeader                  : TImageFileHeader;     OptionalHeader              : TImageOptionalHeader;   END;   PImageExportDirectory         =^TImageExportDirectory;   TImageExportDirectory         = PACKED RECORD     Characteristics             : LongWord;     TimeDateStamp               : LongWord;     MajorVersion                : WORD;     MinorVersion                : WORD;     Name                        : LongWord;     Base                        : LongWord;     NumberOfFunctions           : LongWord;     NumberOfNames               : LongWord;     AddressOfFunctions          :^PLongWord;     AddressOfNames              :^PLongWord;     AddressOfNameOrdinals       :^PWord;   END; VAR   CRC32TAB : ARRAY[0..255] OF DWORD; PROCEDURE BuildCRC32Table; ASSEMBLER; ASM     mov       ebx, 0EDB88320h     lea       edi, crc32tab     xor       ecx, ecx   @loc1:     mov       eax, ecx     mov       edx, 8   @loc2:     test eax, 1     jz  @loc3     shr       eax, 1     xor       eax, ebx     jmp       @loc4   @loc3:     shr       eax, 1   @loc4:     dec       edx     jnz       @loc2     stosd     inc       ecx     cmp       ecx, 256     jb  @loc1 END; FUNCTION CalculateCRC32(VAR Buffer;CONST Size:DWORD) : DWORD; ASSEMBLER; ASM     push esi     push edi     push ebx     mov edi,edx     mov esi,eax     xor ebx,ebx     mov eax,$ffffffff     mov ecx,edi     shr ecx,2     jecxz @Rest   @Loop:     mov edx,[esi]     mov bl,al     xor bl,dl     shr eax,8     xor eax,dword ptr [CRC32tab+ebx*4]     mov bl,al     xor bl,dh     shr eax,8     xor eax,dword ptr [CRC32tab+ebx*4]     shr edx,16     mov bl,al     xor bl,dl     shr eax,8     xor eax,dword ptr [CRC32tab+ebx*4]     mov bl,al     xor bl,dh     shr eax,8     xor eax,dword ptr [CRC32tab+ebx*4]     add esi,4     loop @Loop   @Rest:     mov ecx,edi     and ecx,3     jecxz @End   @Loop_Rest:     mov bl,al     xor bl,[esi]     shr eax,8     inc esi     xor eax,dword ptr [CRC32tab+ebx*4]     loop @Loop_Rest @End:     xor eax,$ffffffff     pop ebx     pop edi     pop esi END; function StrLen(const Str: PChar): Cardinal; assembler; asm   {$IFDEF F_P}         MOV     EAX, [Str]   {$ENDIF F_P}         XCHG    EAX, EDI         XCHG    EDX, EAX         OR      ECX, -1         XOR     EAX, EAX         CMP     EAX, EDI         JE      @@exit0         REPNE   SCASB         DEC     EAX         DEC     EAX         SUB     EAX,ECX @@exit0:         MOV     EDI,EDX end {$IFDEF F_P} [ 'EAX', 'EDX', 'ECX' ] {$ENDIF}; //------------------------------------------------------------------------------ FUNCTION GetProcAddress(Module:Cardinal;ProcessCRC:DWORD) : Pointer; VAR   ExportName           : pChar;   Address              : Cardinal;   J                    : Cardinal;   ImageDosHeader       : PImageDosHeader;   ImageNTHeaders       : PImageNTHeaders;   ImageExportDirectory : PImageExportDirectory; BEGIN   ImageDosHeader:=Pointer(Module);   ImageNTHeaders:=Pointer(Module+ImageDosHeader._lfanew);   ImageExportDirectory:=Pointer(ImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress+Module);   J:=0;   Address:=0;   REPEAT     ExportName:=Pointer(Cardinal(Pointer(Cardinal(ImageExportDirectory.AddressOfNames)+Module+J*4)^)+Module);     IF CalculateCRC32(ExportName^,StrLen(ExportName))=ProcessCRC THEN       Address:=Cardinal(Pointer(Word(Pointer(J SHL 1+Cardinal(                ImageExportDirectory.AddressOfNameOrdinals)+Module)^) AND                $0000FFFF SHL 2+Cardinal(ImageExportDirectory.AddressOfFunctions)                +Module)^)+Module;     Inc(J);   UNTIL (Address<>0)OR(J=ImageExportDirectory.NumberOfNames);   Result:=Pointer(Address); END; FUNCTION MyLoadLibraryA:Pointer; const   MyLoadLibraryA=$3FC1BD8D;//LoadLibraryA的Crc32数值 asm   mov eax,fs:$30        mov eax,[eax + $0c]        mov esi,[eax + $1c]        lodsd        mov eax,[eax+$08]   mov edx,MyLoadLibraryA   call GetProcAddress end; procedure ExitProcess; external kernel32 name 'ExitProcess' procedure _InitExe; asm end; procedure _HandleFinally; asm end; procedure _halt0;                 //由于Win2k下无导入表的程序无法运行 asm   PUSH ExitCode   CALL ExitProcess               //这里保留了一个ExitProcess end;                        //您可以删除这个地方的代码~编译后使用Upack加壳也可以Run end.



主程序代码

代码:
{   Anskya NoImport APISearchEngine Demo By Anskya   Email:Anskya@Gmail.com   Web:Www.Anskya.Net   QQ:115447 } PROGRAM Project; CONST   MessageBoxA = $572D5D8E; //的Crc32数值 VAR   MessageBox : FUNCTION(hWnd:longWord;lpText,lpCaption:PChar;uType:longWord) : Integer; STDCALL;   LoadLibrary:function(lpLibFileName: PChar): longWord; stdcall; BEGIN   BuildCRC32Table;   @LoadLibrary:=MyLoadLibraryA;   MessageBox:=GetProcAddress(LoadLibrary('user32.dll'),MessageBoxA);   Messagebox(0,'无导入表EXE[Win2k下PE没有导入表无法运行所以保留ExitProcess函数]','By Anskya!',0); END.



到此程序基本上完成了~测试了Win2k,XP,2k3都可以正常运行
(实在找不到Win9x测试了~~不好意思)

附件有完整的程序代码和~编译说明以及演示图片
//The_end~~

程序编译后4k压缩一下1.13k(for Delphi 6)