Delphi是最适合编写ShellCode的工具

本文介绍了一种使用Borland编译器优化ShellCode的方法,通过特殊的字符串处理技巧,使得字符串能在代码段内动态定位,从而避免了传统方法中的字符串常量区读取限制。此外,还提供了一个改进版GetProcAddress函数的例子,演示了如何直接使用函数名而不需要预计算CRC。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文是写给经常写ShellCode或者给PE文件添加代码的人的. 
题目这样写有点不精确.不过Borland的编译器确实是算得上最适合编写ShellCode工具.
编写ShellCode的朋友们知道.字符串常量应该是处理起来非常麻烦.
例如:
调用GetProcAddress函数吧.参数有一个是字符串.很多编译器字符串常量是在数据段中.只读的属性.
那么编写ShellCode的时候GetProcAddress(hm,"Function");就不行了.因为"Function"实际上是在数据段中,传递的只是指针.如果是DLL的话可能还要重定位.
所以见到有很多人编写ShellCode自己实现GetProcAddress.用的是函数名的CRC.
 
 
Borland的编译器有一个特点.正好可以利用.它编译的时候字符串常量不是放在数据段里面.而是放到所在函数的后面.以Delphi为例.
 
Function A():PChar;
begin
  Result := 'abc';
end;
实际上在编译后变成
00453BF0 B8F83B4500       mov eax,$00453bf8 //把字符串abc的地址付给eax,eax是返回值
00453BF5 C3               ret               //返回
00453BF6 0000                               //实际上是没用.作用是对齐代码
00453BF8 61626300         字符串abc
 
但是现在你还不能把这份代码作为ShellCode拷贝到任意地方使用.应为 mov eax,$00453bf8 的参数是绝对地址.我们怎么把它转化成相对的呢?
这需要一个技巧.

Function FixPChar(Value : PChar):PChar;forward;

Function A():PChar;
begin
  Result := FixPChar('abc');
end;

Function FixPChar(Value : PChar):PChar; register;//register;加不加都无所谓.默认就是register;
asm
          call   @next                //
@next:    pop    ecx                  //ecx里面装的就是@next的相对地址,当前执行时
          mov    ebx, offset @next    //ebx里面装的就是@next的绝对地址,编译时生成的
          add    eax, ecx             //返回Value的地址+(相对地址-绝对地址)
          sub    eax, ebx
end;


procedure _end();
begin

end;

 

现在我们可以把A函数和FixChar拷贝到任何地方使用了.如何拷贝呢?

我们只要拷贝A函数的地址为起始,_end函数的地址为终点的数据块就可以用了.

例如

Type
  TFunc = Function():PChar;
var
  M : String;
begin
  //
  SetLength(M, Integer(@_end) - Integer(@A)); //为M分配长度
  CopyMemory(PChar(M), @A, Length(M));        //把A函数和_end之间的代码拷贝到M
  ShowMessage(TFunc(PChar(M))());             //把M强制转换为TFunc类型执行
end;

 

网上流传很广的一个API搜索就是用CRC来避开字符串的.如果用这样的技术完全可以省略计算CRC的步骤.

原函数如下: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 FixPChar(Value: PChar): PChar; forward;

function strcmp(p1, p2: PChar): boolean; forward;

function GetProcAddress(Module: Cardinal; ProcessName: PChar): 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 strcmp(ExportName, ProcessName) 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 strcmp(p1, p2: PChar): boolean;
begin
  Result := False;
  while (p1^ = p2^) do
  begin
    if (P1^ = #0) or (P2^ = #0) then
    begin
      Result := True;
      Exit;
    end;

    Inc(P1);
    Inc(P2);
  end;

end;

function FixPChar(Value: PChar): PChar; register; //register;加不加都无所谓.默认就是register;
asm
          call   @next                //
@next:    pop    ecx                  //ecx里面装的就是@next的相对地址,当前执行时
          mov    ebx, offset @next    //ebx里面装的就是@next的绝对地址,编译时生成的
          add    eax, ecx             //返回Value的地址+(相对地址-绝对地址)
          sub    eax, ebx
end;


procedure _end();
begin

end;

 调用的时候直接  GetProcAddress(hm,FixPChar('函数名'));就可以了.免了事先计算函数名CRC的麻烦.

 
Shellcode Helper v1.62 Coded by TeLeMan (c) 2008-2013 Usage: schelper.exe [options] Options: -i [input file] input file (Default: stdin) -o [output file] output file (Default: stdout) -s input file format (Default: Auto-Detection) -sb input file format is Binary -sp the input file format's parameters -d output file format (Default: C format) -db output file format is Binary -dp the output file format's parameters -search get the start offset by the pattern: e.g. PK\x03\x04 -soff fix the match offset after searching (Default: 0) -off convert the input file from the offset (Default: 0) -len convert the input file with the length (Default: 0 - MAX) -en [encoder] encode shellcode (Default: XorDword) -de [encoder] decode shellcode (Default: Auto-Detection) -ex exclude characters: e.g. 0x00,0x01-0x1F,0xFF (Default: 0x00) -in incude characters only -ep the encoder's parameters -t [pid] execute or inject shellcode into process for testing -td [pid] execute or inject shellcode into process for debugging -stack put shellcode into stack and execute it (ESP is the shellcode start) -noinfo display no normal messages except error messages Available formats: 0 - C 1 - C(HexArray) 2 - Perl 3 - Python 4 - Ruby 5 - JavaScript(Escape) 6 - VBScript(Escape) 7 - Pascal 8 - MASM(Data) 9 - HexDump 10 - BitString 11 - HexString 12 - HexArray(C like) 13 - Base64 14 - Binary 15 - HexString(C like) 16 - HexString(Escape) 17 - HexString(JavaScript,UNICODE) 18 - URI(ISO-8859-1) 19 - XML(PCDATA) 20 - BigNumber 21 - BigNumber(Hex) 22 - BigNumber(BaseX) 23 - FloatPoint 24 - UnixTimestamp 25 - GUID 26 - MASM(ASM) 27 - NASM 28 - YASM(ASM) 29 - FASM(ASM) 30 - JWASM(ASM) 31 - POASM(ASM) 32 - GOASM(ASM) 33 - GNU ASM Available encoders:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值