我是靠谱客的博主 大力睫毛,最近开发中收集的这篇文章主要介绍Delphi是最适合编写ShellCode的工具,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

本文是写给经常写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的麻烦.

 

最后

以上就是大力睫毛为你收集整理的Delphi是最适合编写ShellCode的工具的全部内容,希望文章能够帮你解决Delphi是最适合编写ShellCode的工具所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(45)

评论列表共有 0 条评论

立即
投稿
返回
顶部