邪恶八进制信息安全团队技术讨论组's Archiver

ring04h 2006-2-8 10:38

[转载]Delphi下构建无导入表程序-使用:hash获取API,k32Base等

<P>文章作者:anskya</P><FONT face=宋体>《Delphi实现无导入表程序》<BR>初学编程,请勿奸笑:P<BR>首先感谢,一些认识不认识的前辈高人的资料.谢谢~<BR><BR>前提假设您已经有了一定的PEVirus的知识.<BR>好了~先简单的说说无导入表程序的几点基本的构成<BR>1.GetkernelBase(获取kernel32.dll的基址)<BR>由于我们是无导入表的程序所以,所有API函数都是依靠内存搜索完成的,<BR>想必大家已经知道EXE载入到内存中ESP保存ExitThread函数地址<BR>ExitThread函数是在kernel32.dll模块中的,所以证明EXE载入的时候就已经加载<BR>了kernel32.dll模块,于是我们的工作就是确定kernel32.dll的基址。<BR><BR>这里我使用"PEB获取地址kernel32.dll基址"的方法(简单嘛。。Delphi调试这种程序很麻烦的~所以使用这个。。)<BR></FONT>
<BLOCKQUOTE><PRE><FONT face=宋体>代码:</FONT><HR>
asm
moveax,fs:$30
moveax,[eax+$0c]
movesi,[eax+$1c]
lodsd
moveax,[eax+$08]//这个时候eax中保存的就是k32的基址了
end;
<HR></PRE></BLOCKQUOTE><FONT face=宋体><BR>基址获取到了剩下的就是需要确定我们需要的两个重要的函数<BR>"GetProcAddress"和"LoadLibraryA"两个函数~有了这两个函数我们就可以<BR>获取到我们需要的任何函数了..<BR><BR>2.自构建"GetProcAddress"函数<BR>上面我们已经获取到k32的基址了~但是问题是我们还需要一些其他函数来完成我们程序<BR>的功能,首先我们回顾一下~前辈们写的API搜索函数,为了减少程序体积和保护程序自身<BR>他们基本上都是使用hash值来搜索模块的导入表的,这样我们就可以自己构建一个API搜索<BR>函数了。直接贴代码好了~其实Delphi版本的API搜索函数许多前辈都写过<BR>Aming,老王,liumazi等等~<BR></FONT>
<BLOCKQUOTE><PRE><FONT face=宋体>代码:</FONT><HR>
FUNCTIONGetProcAddress(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);
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;
<HR></PRE></BLOCKQUOTE><FONT face=宋体><BR>好了~此函数就可以帮我们,循环对比ProcessCRC参数中给出的API的hash值<BR>然后发挥这个函数的地址,我这里使用的是Crc32算法~<BR>上面的PE的数据结构可以从Windows中Copy出来<BR><BR></FONT>
<BLOCKQUOTE><PRE><FONT face=宋体>代码:</FONT><HR>
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;CONSTSize:DWORD):DWORD;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;
<HR></PRE></BLOCKQUOTE><FONT face=宋体><BR>这个是计算一个数据的Crc32数值--返回是10进制的~可以自己改变成16进制<BR><BR>好了现在我们已经有了GetProcAddress函数了~好像还少一个??<BR>前面我们提到过需要两个函数~GetProcAddress有了·k32的基址也有了<BR>这样我们就可以搜索出LoadLibraryA的地址....<BR>好了完成前面的代码<BR></FONT>
<BLOCKQUOTE><PRE><FONT face=宋体>代码:</FONT><HR>
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;
<HR></PRE></BLOCKQUOTE><FONT face=宋体><BR><BR>好了现在我们两个函数都有了~现在我们的任务已经完成一半了!<BR>(为什么是一半??因为Delphi非等同于VC和XXXASM,他不能够自己构建PE结构)<BR>准确的说~即使你写一个只有一条beginend.的程序~编译器编译的时候还是会连接N多<BR>的API函数~进来....<BR>为了完成任务,我们这里就使用了NicoBendlin前辈的miniEXE的模板...<BR>自己打造了一个无导入表的程序...<BR>这里需要我们自己编译system.pas和SysInit.pas单元<BR></FONT>
<BLOCKQUOTE><PRE><FONT face=宋体>代码:</FONT><HR>
//SysInit.pas单元代码
unitSysInit;

interface

var
TlsIndex:LongWord;

implementation

end.
<HR></PRE></BLOCKQUOTE><FONT face=宋体><BR>System.pas单元代码<BR></FONT>
<BLOCKQUOTE><PRE><FONT face=宋体>代码:</FONT><HR>
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;CONSTSize:DWORD):DWORD;
FUNCTIONGetProcAddress(Module:Cardinal;ProcessCRC:DWORD):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;CONSTSize:DWORD):DWORD;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;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);
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.
<HR></PRE></BLOCKQUOTE><FONT face=宋体><BR><BR>主程序代码<BR></FONT>
<BLOCKQUOTE><PRE><FONT face=宋体>代码:</FONT><HR>
{
AnskyaNoImportAPISearchEngineDemoByAnskya
Email:Anskya@Gmail.com
Web:<A href="http://www.anskya.net/" target=_blank><FONT color=#000000>Www.Anskya.Net</FONT></A>
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.
<HR></PRE></BLOCKQUOTE><FONT face=宋体><BR><BR>到此程序基本上完成了~测试了Win2k,XP,2k3都可以正常运行<BR>(实在找不到Win9x测试了~~不好意思)<BR><BR>附件有完整的程序代码和~编译说明以及演示图片<BR>//The_end~~<BR><BR>程序编译后4k压缩一下1.13k(forDelphi6)<BR></FONT>
<P></P>

页: [1]
© 1999-2008 EvilOctal Security Team