安全中国首页 > 文章中心 > 加壳技术
 
安全中国网友投稿专用上传FTP空间:
Ftp服务器:download.anqn.com
Ftp端口:21
用户名:anqn
密 码:anqn.com
 

打造MyGetProcAddress函数(Delphi源码)

更新时间:2007-9-27 20:19:06
责任编辑:池天
热 点:

function MyGetProcAddress(hModule: HMODULE; lpProcName: LPCSTR): FARPROC; stdcall;

function MyGetProcAddress(hModule: HMODULE; lpProcName: LPCSTR): FARPROC;
var
  DataDirectory: TImageDataDirectory;
  P1: ^Cardinal;
  P2: ^Word;
  Base, NumberOfNames, AddressOfFunctions, AddressOfNames, AddressOfNameOrdinals, i, Ordinal: Cardinal;
  TempStr1, TempStr2: string;
begin
  Result := nil;
  DataDirectory := PImageNtHeaders(Cardinal(hModule) + Cardinal(PImageDosHeader(hModule)^._lfanew))^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
  P1 := Pointer(hModule + DataDirectory.VirtualAddress + 16);
  Base := P1^; //输出函数的起始序号。一般为1。
  P1 := Pointer(hModule + DataDirectory.VirtualAddress + 24);
  NumberOfNames := P1^; //输出函数名的指针的数组中的元素个数,也是输出函数名对应的序号的数组中的元素个数。
  P1 := Pointer(hModule + DataDirectory.VirtualAddress + 28);
  AddressOfFunctions := P1^; //一个RVA,指向输出函数入口地址的数组。
  P1 := Pointer(hModule + DataDirectory.VirtualAddress + 32);
  AddressOfNames := P1^; //一个RVA,指向输出函数名的指针的数组。
  P1 := Pointer(hModule + DataDirectory.VirtualAddress + 36);
  AddressOfNameOrdinals := P1^; //一个RVA,指向输出函数名对应的序号的数组。
  Ordinal := 0;
  if Cardinal(lpProcName) > $0000FFFF then
  begin
    //lpProcName参数指向函数名
    TempStr1 := PChar(lpProcName); //要找的函数名
    for i := 1 to NumberOfNames do
    begin
      //按顺序在输出函数名中找
      P1 := Pointer(hModule + AddressOfNames + (i - 1) * 4);
      TempStr2 := PChar(hModule + P1^); //当前输出函数名
      if TempStr1 = TempStr2 then
      begin
        //找到输出函数
        P2 := Pointer(hModule + AddressOfNameOrdinals + (i - 1) * 2);
        //获得序号,不必减Base
        Ordinal := P2^;
        Break;
      end;
    end;
  end
  else
    //lpProcName传过来的是序号,需减Base
    Ordinal := Cardinal(lpProcName) - Base;
  P1 := Pointer(hModule + AddressOfFunctions + Ordinal * 4); //P1^为函数入口RVA
  if (P1^ >= DataDirectory.VirtualAddress) and (P1^ <= DataDirectory.VirtualAddress + DataDirectory.Size) then
  begin
    //!!!入口RVA在输出表中,指向另一DLL的某函数,这一点很容易被忽视,很少有教程提到,也许是没仔细看!!!
    TempStr1 := PChar(hModule + P1^); //DLL.函数
    TempStr2 := TempStr1;
    while Pos('.', TempStr2) > 0 do
      TempStr2 := Copy(TempStr2, Pos('.', TempStr2) + 1, Length(TempStr2) - Pos('.', TempStr2));
    TempStr1 := Copy(TempStr1, 1, Length(TempStr1) - Length(TempStr2) - 1); //TempStr1是DLL名,TempStr2是函数名
    //递归调用获取新的函数地址
    Base := GetModuleHandle(PChar(TempStr1));
    if Base = 0 then
      Base := LoadLibrary(PChar(TempStr1));
    if Base > 0 then
      Result := MyGetProcAddress(Base, PChar(TempStr2));
  end
  else
    //RVA+基址就是函数的真实入口了
    Result := Pointer(hModule + P1^);
  //结果Result := GetProcAddress(hModule, lpProcName);
end;

相关:
  _IMAGE_DATA_DIRECTORY = record
    VirtualAddress: DWORD;
    Size: DWORD;
  end;
  {$EXTERNALSYM _IMAGE_DATA_DIRECTORY}
  TImageDataDirectory = _IMAGE_DATA_DIRECTORY;

  PImageExportDirectory = ^TImageExportDirectory;
  _IMAGE_EXPORT_DIRECTORY = packed record
      Characteristics: DWord;
      TimeDateStamp: DWord;
      MajorVersion: Word;
      MinorVersion: Word;
      Name: DWord;
      Base: DWord;
      NumberOfFunctions: DWord;
      NumberOfNames: DWord;
      AddressOfFunctions: ^PDWORD;
      AddressOfNames: ^PDWORD;
      AddressOfNameOrdinals: ^PWord;
  end;
  {$EXTERNALSYM _IMAGE_EXPORT_DIRECTORY}
  TImageExportDirectory = _IMAGE_EXPORT_DIRECTORY;

这是我用来在EncryptPE新版壳中处理IAT的源代码,98、2003下测试通过。如果你发现问题请告诉我!
假如你是Cracker,看到这段代码,你准备如何设断,避开IAT加密呢?

EncryptPE作者老王(wfs)
2004.5.6

1 2 下一页

 
相关文章
一日一文章
 
一日一软件
一日一动画