2009-10-26 | #1 (permalink) |
高级会员
注册日期: 2009-07-09
住址: 亦庄经济开发区2号院大族广场1502
帖子: 531
|
Delphi下构建无导入表程序--使用hash获取API
前提假设您已经有了一定的PEVirus的知识.
好了~先简单的说说无导入表程序的几点基本的构成 1.GetkernelBase(获取kernel32.dll的基址) 由于我们是无导入表的程序所以,所有API函数都是依靠内存搜索完成的, 想必大家已经知道EXE载入到内存中ESP保存ExitThread函数地址 ExitThread函数是在kernel32.dll模块中的,所以证明EXE载入的时候就已经加载 了kernel32.dll模块,于是我们的工作就是确定kernel32.dll的基址。 这里我使用"PEB获取地址kernel32.dll基址"的方法(简单嘛。。Delphi调试这种程序很麻烦的~所以使用这个。。) 代码:-------------------------------------------------------------------------------- asm moveax,fs:$30 moveax,[eax+$0c] movesi,[eax+$1c] lodsd moveax,[eax+$08]//这个时候eax中保存的就是k32的基址了 end; -------------------------------------------------------------------------------- 基址获取到了剩下的就是需要确定我们需要的两个重要的函数 "GetProcAddress"和"LoadLibraryA"两个函数~有了这两个函数我们就可以 获取到我们需要的任何函数了.. 2.自构建"GetProcAddress"函数 上面我们已经获取到k32的基址了~但是问题是我们还需要一些其他函数来完成我们程序 的功能,首先我们回顾一下~前辈们写的API搜索函数,为了减少程序体积和保护程序自身 他们基本上都是使用hash值来搜索模块的导入表的,这样我们就可以自己构建一个API搜索 函数了。直接贴代码好了~其实Delphi版本的API搜索函数许多前辈都写过 Aming,老王,liumazi等等~ 代码:-------------------------------------------------------------------------------- FUNCTIONGetProcAddress(Module:Cardinal;ProcessCRCWORD):Pointer; VAR ExportNameChar; 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); IFCalculateCRC32(ExportName^,StrLen(ExportName))=ProcessCRCTHEN Address:=Cardinal(Pointer(Word(Pointer(JSHL1+Cardinal( ImageExportDirectory.AddressOfNameOrdinals)+Module)^)AND $0000FFFFSHL2+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出来 代码:-------------------------------------------------------------------------------- PROCEDUREBuildCRC32Table;ASSEMBLER; ASM movebx,0EDB88320h leaedi,crc32tab xorecx,ecx @loc1: moveax,ecx movedx,8 @loc2: testeax,1 jz@loc3 shreax,1 xoreax,ebx jmp@loc4 @loc3: shreax,1 @loc4: decedx jnz@loc2 stosd incecx cmpecx,256 jb@loc1 END; FUNCTIONCalculateCRC32(VARBuffer;CONSTSizeWORD)WORD;ASSEMBLER; ASM pushesi pushedi pushebx movedi,edx movesi,eax xorebx,ebx moveax,$ffffffff movecx,edi shrecx,2 jecxz@Rest @Loop: movedx,[esi] movbl,al xorbl,dl shreax,8 xoreax,dwordptr[CRC32tab+ebx*4] movbl,al xorbl,dh shreax,8 xoreax,dwordptr[CRC32tab+ebx*4] shredx,16 movbl,al xorbl,dl shreax,8 xoreax,dwordptr[CRC32tab+ebx*4] movbl,al xorbl,dh shreax,8 xoreax,dwordptr[CRC32tab+ebx*4] addesi,4 loop@Loop @Rest: movecx,edi andecx,3 jecxz@End @Loop_Rest: movbl,al xorbl,[esi] shreax,8 incesi xoreax,dwordptr[CRC32tab+ebx*4] loop@Loop_Rest @End: xoreax,$ffffffff popebx popedi popesi END; -------------------------------------------------------------------------------- 这个是计算一个数据的Crc32数值--返回是10进制的~可以自己改变成16进制 好了现在我们已经有了GetProcAddress函数了~好像还少一个?? 前面我们提到过需要两个函数~GetProcAddress有了·k32的基址也有了 这样我们就可以搜索出LoadLibraryA的地址.... 好了完成前面的代码 代码:-------------------------------------------------------------------------------- FUNCTIONMyLoadLibraryA:Pointer; const MyLoadLibraryA=$3FC1BD8D;//LoadLibraryA的Crc32数值 asm moveax,fs:$30 moveax,[eax+$0c] movesi,[eax+$1c] lodsd moveax,[eax+$08]//此时eax中就保存了k32的基址 movedx,MyLoadLibraryA//压入LoadLibraryA的Hash callGetProcAddress//开始获取LoadLibraryA的地址 end; -------------------------------------------------------------------------------- 好了现在我们两个函数都有了~现在我们的任务已经完成一半了! (为什么是一半??因为Delphi非等同于VC和XXXASM,他不能够自己构建PE结构) 准确的说~即使你写一个只有一条beginend.的程序~编译器编译的时候还是会连接N多 的API函数~进来.... 为了完成任务,我们这里就使用了NicoBendlin前辈的miniEXE的模板... 自己打造了一个无导入表的程序... 这里需要我们自己编译system.pas和SysInit.pas单元 代码:-------------------------------------------------------------------------------- //SysInit.pas单元代码 unitSysInit; interface var TlsIndex:LongWord; implementation end. -------------------------------------------------------------------------------- System.pas单元代码 代码:-------------------------------------------------------------------------------- unitSystem; interface type DWORD=LongWord; PLongWord=^LongWord; PWord=^Word; TGUID=record D1:LongWord; D2:Word; D3:Word; D4:array[0..7]ofByte; end; const Kernel32='kernel32.dll' var ExitCode:LongWord; HKernel32:LongWord; procedure_InitExe; procedure_HandleFinally; procedure_halt0; PROCEDUREBuildCRC32Table; //procedureExitProcess(uExitCode:LongWord);stdcall; FUNCTIONCalculateCRC32(VARBuffer;CONSTSizeWORD)WORD; FUNCTIONGetProcAddress(Module:Cardinal;ProcessCRCWORD):Pointer; FUNCTIONMyLoadLibraryA: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=PACKEDRECORD 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]OFWORD; e_oemid:WORD; e_oeminfo:WORD; e_res2:ARRAY[0..9]OFWORD; _lfanew:LongInt; END; PImageFileHeader=^TImageFileHeader; TImageFileHeader=PACKEDRECORD 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=PACKEDRECORD 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:PACKEDARRAY[0..IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1]OFTImageDataDirectory; END; PImageNtHeaders=^TImageNtHeaders; TImageNtHeaders=PACKEDRECORD Signature:LongWord; FileHeader:TImageFileHeader; OptionalHeader:TImageOptionalHeader; END; PImageExportDirectory=^TImageExportDirectory; TImageExportDirectory=PACKEDRECORD 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]OFDWORD; PROCEDUREBuildCRC32Table;ASSEMBLER; ASM movebx,0EDB88320h leaedi,crc32tab xorecx,ecx @loc1: moveax,ecx movedx,8 @loc2: testeax,1 jz@loc3 shreax,1 xoreax,ebx jmp@loc4 @loc3: shreax,1 @loc4: decedx jnz@loc2 stosd incecx cmpecx,256 jb@loc1 END; FUNCTIONCalculateCRC32(VARBuffer;CONSTSizeWORD)WORD;ASSEMBLER; ASM pushesi pushedi pushebx movedi,edx movesi,eax xorebx,ebx moveax,$ffffffff movecx,edi shrecx,2 jecxz@Rest @Loop: movedx,[esi] movbl,al xorbl,dl shreax,8 xoreax,dwordptr[CRC32tab+ebx*4] movbl,al xorbl,dh shreax,8 xoreax,dwordptr[CRC32tab+ebx*4] shredx,16 movbl,al xorbl,dl shreax,8 xoreax,dwordptr[CRC32tab+ebx*4] movbl,al xorbl,dh shreax,8 xoreax,dwordptr[CRC32tab+ebx*4] addesi,4 loop@Loop @Rest: movecx,edi andecx,3 jecxz@End @Loop_Rest: movbl,al xorbl,[esi] shreax,8 incesi xoreax,dwordptr[CRC32tab+ebx*4] loop@Loop_Rest @End: xoreax,$ffffffff popebx popedi popesi END; functionStrLen(constStr:PChar):Cardinal;assembler; asm {$IFDEFF_P} MOVEAX,[Str] {$ENDIFF_P} XCHGEAX,EDI XCHGEDX,EAX ORECX,-1 XOREAX,EAX CMPEAX,EDI JE@@exit0 REPNESCASB DECEAX DECEAX SUBEAX,ECX @@exit0: MOVEDI,EDX end{$IFDEFF_P}['EAX','EDX','ECX']{$ENDIF}; //------------------------------------------------------------------------------ FUNCTIONGetProcAddress(Module:Cardinal;ProcessCRCWORD):Pointer; VAR ExportNameChar; 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); IFCalculateCRC32(ExportName^,StrLen(ExportName))=ProcessCRCTHEN Address:=Cardinal(Pointer(Word(Pointer(JSHL1+Cardinal( ImageExportDirectory.AddressOfNameOrdinals)+Module)^)AND $0000FFFFSHL2+Cardinal(ImageExportDirectory.AddressOfFunctions) +Module)^)+Module; Inc(J); UNTIL(Address<>0)OR(J=ImageExportDirectory.NumberOfNames); Result:=Pointer(Address); END; FUNCTIONMyLoadLibraryA:Pointer; const MyLoadLibraryA=$3FC1BD8D;//LoadLibraryA的Crc32数值 asm moveax,fs:$30 moveax,[eax+$0c] movesi,[eax+$1c] lodsd moveax,[eax+$08] movedx,MyLoadLibraryA callGetProcAddress end; procedureExitProcess;externalkernel32name'ExitProcess' procedure_InitExe; asm end; procedure_HandleFinally; asm end; procedure_halt0;//由于Win2k下无导入表的程序无法运行 asm PUSHExitCode CALLExitProcess//这里保留了一个ExitProcess end;//您可以删除这个地方的代码~编译后使用Upack加壳也可以Run end. -------------------------------------------------------------------------------- 主程序代码 代码:-------------------------------------------------------------------------------- { AnskyaNoImportAPISearchEngineDemoByAnskya Email:Anskya@Gmail.com Web:Www.Anskya.Net QQ:115447 } PROGRAMProject; 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函数]','ByAnskya!',0); END. -------------------------------------------------------------------------------- 到此程序基本上完成了~测试了Win2k,XP,2k3都可以正常运行 (实在找不到Win9x测试了~~不好意思) 附件有完整的程序代码和~编译说明以及演示图片 //The_end~~ 程序编译后4k压缩一下1.13k(forDelphi6)
__________________
地址:北京亦庄经济技术开发区荣华南路10号院5号楼705 电话:010-82356575/76/77转6070 联系人:苏秋英 手机微信同号:13811870548 QQ: 1170923055 |