Psychlo

Members
  • Content count

    154
  • Joined

  • Last visited

Community Reputation

39 Excellent

About Psychlo

  • Rank
    Senior Member
  • Birthday 09/19/1987
  1. Didn`t forget the project haha unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, hde64, uBytesToPascal2, uHook64; type TForm1 = class(TForm) Button1: TButton; Memo1: TMemo; Button2: TButton; Button3: TButton; Button4: TButton; Button5: TButton; Button6: TButton; Edit1: TEdit; Button7: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button4Click(Sender: TObject); procedure Button3Click(Sender: TObject); procedure Button5Click(Sender: TObject); procedure Button6Click(Sender: TObject); procedure Button7Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; HOriginal_MessageBoxW: function (p1: Int64; lpText, lpCaption: PWideChar; p4: Cardinal): Integer; stdcall = nil; implementation {$R *.dfm} function CreateTrampolineFunction(p, pTrampoline: Pointer): Boolean; var hs: TDisasm; bFinished: Boolean; opcodes: String; c: Integer; dwDisasmBytes: Cardinal; dwTotalDisasmBytes: Cardinal; pCurrentInstructionAddr: Pointer; pCopyAddress: Pointer; pCopySrc: Pointer; dwCopySize: NativeUInt; arrBuffer: Array [0..15] of Byte; pRelAddress: PCardinal; Trampoline64_ReturnOriginal: TTrampoline64; Trampoline64Call_Redirect: TTrampolineCall64; begin Result := False; bFinished := False; dwTotalDisasmBytes := 0; pCopyAddress := pTrampoline; pCopySrc := nil; dwCopySize := 0; repeat try pCurrentInstructionAddr := Pointer(UInt64(p) + dwTotalDisasmBytes); dwDisasmBytes := hde64_disasm(pCurrentInstructionAddr, hs); opcodes := ''; for c := 0 to dwDisasmBytes - 1 do begin opcodes := opcodes + IntToHex(PByte(UInt64(pCurrentInstructionAddr) + c)^, 2) + ' '; end; Form1.Memo1.Lines.Add('$' + IntToHex(UInt64(pCurrentInstructionAddr), 16) + ' len(' + IntToStr(hs.len) + ') ' + opcodes); if ((hs.flags and F_ERROR) <> 0) then begin Result := False; Break; end; pCopySrc := pCurrentInstructionAddr; dwCopySize := hs.len; //if (dwTotalDisasmBytes >= SizeOf(TTrampoline64)) then if (dwTotalDisasmBytes >= 83) then begin Form1.Memo1.Lines.Add('Necessary space reached, copying jump instructions.'); Trampoline64_ReturnOriginal := Trampoline64_DefaultValues; Trampoline64_ReturnOriginal.asmAddress := UInt64(p) + dwTotalDisasmBytes; pCopySrc := @Trampoline64_ReturnOriginal; dwCopySize := SizeOf(TTrampoline64); bFinished := True; Result := True; end // Instructions using RIP relative addressing. (ModR/M = 00???101B) else if ((hs.modrm and $C7) = $05) then begin // Relative address is stored at (instruction length - immediate value length - 4). CopyMemory(@arrBuffer[0], pCurrentInstructionAddr, hs.len); pRelAddress := Pointer(UInt64(@arrBuffer[0]) + hs.len - ((hs.flags and $3C) shr 2) - 4); pRelAddress^ := Cardinal( (UInt64(pCurrentInstructionAddr) - UInt64(pCopyAddress) + hs.disp.disp32) ); pCopySrc := @arrBuffer[0]; Form1.Memo1.Lines.Add('Instruction using RIP relative addressing ($' + IntToHex(PCardinal( UInt64(pCurrentInstructionAddr) + hs.len - ((hs.flags and $3C) shr 2) - 4 )^, 8) + ').'); Form1.Memo1.Lines.Add('Flags = $' + IntToHex(((hs.flags and $3C) shr 2), 8)); //hs.len - ((hs.flags and $3C) shr 2) Form1.Memo1.Lines.Add('disp32 = $' + IntToHex(hs.disp.disp32, 8)); Form1.Memo1.Lines.Add('Address = $' + IntToHex(UInt64(pCurrentInstructionAddr) + hs.len + hs.disp.disp32, 16)); end // Direct relative CALL else if (hs.opcode = $E8) then begin Form1.Memo1.Lines.Add('Direct relative CALL.'); Form1.Memo1.Lines.Add('hs.imm.imm32 = $' + IntToHex(hs.imm.imm32, 8)); Form1.Memo1.Lines.Add('RELATIVE CALL ($' + IntToHex(Cardinal( UInt64(pCurrentInstructionAddr) + hs.len + Integer(hs.imm.imm32) ), 8) + ').'); Trampoline64Call_Redirect := TrampolineCall64_DefaultValues; Trampoline64Call_Redirect.asmAddress := UInt64( UInt64(pCurrentInstructionAddr) + hs.len + Integer(hs.imm.imm32) ); pCopySrc := @Trampoline64Call_Redirect; dwCopySize := SizeOf(TTrampolineCall64); end // Direct relative JMP (EB or E9) else if ((hs.opcode and $FD) = $E9) then begin Form1.Memo1.Lines.Add('Direct relative JMP (EB or E9).'); end // Direct relative Jcc else if ((hs.opcode and $F0) = $70) or ((hs.opcode and $FC) = $E0) or ((hs.opcode2 and $F0) = $80) then begin Form1.Memo1.Lines.Add('Direct relative Jcc.'); end // RET (C2 or C3) else if ((hs.opcode and $FE) = $C2) then begin bFinished := True; Result := True; end; if ((pCopySrc <> nil) and (dwCopySize > 0)) then begin CopyMemory(pCopyAddress, pCopySrc, dwCopySize); pCopyAddress := Pointer(UInt64(pCopyAddress) + dwCopySize); end; dwTotalDisasmBytes := dwTotalDisasmBytes + dwDisasmBytes; except Result := False; Break; end; until (bFinished); end; function Hook_MessageBoxW(p1: Int64; lpText, lpCaption: PWideChar; p4: Cardinal): Integer; stdcall; var strText, strCaption: String; begin //Result := 0; strText := WideCharToString(lpText); strCaption := WideCharToString(lpCaption); Form1.Memo1.Lines.Add('Intercepted: ' + strText + ' - ' + strCaption); //MessageBoxA(0, PChar(strText), PChar(strCaption), MB_OK); Result := HOriginal_MessageBoxW(p1, lpText, lpCaption, p4); end; procedure Test; begin MessageBoxW(0, 'Test', 'Program', MB_OK); end; procedure TForm1.Button1Click(Sender: TObject); var hs: TDisasm; i, c, len, offset: Integer; opcodes: String; begin offset := 0; for i := 0 to 10 - 1 do begin len := hde64_disasm(Pointer(UInt64(GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')) + offset), hs); opcodes := ''; for c := 0 to len - 1 do begin opcodes := opcodes + IntToHex(PByte(UInt64(GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')) + offset + c)^, 2) + ' '; end; Memo1.Lines.Add(opcodes); offset := offset + len; end; //Memo1.Lines.Add(IntToStr( )); end; procedure TForm1.Button2Click(Sender: TObject); begin Memo1.Lines.Add(IntToStr(GetMinHookLength(16, GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')))); end; procedure TForm1.Button3Click(Sender: TObject); begin Test; end; procedure TForm1.Button4Click(Sender: TObject); begin HOriginal_MessageBoxW := InstallHook64(@Hook_MessageBoxW, GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')); if (@HOriginal_MessageBoxW <> nil) then begin Memo1.Lines.Add('Hook installed successfully! -- pFunction = ' + IntToHex(UInt64( GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')), 16)); end; end; procedure TForm1.Button5Click(Sender: TObject); var hs: TDisasm; i, c, len, offset: Integer; opcodes: String; begin offset := 0; for i := 0 to 10 - 1 do begin len := hde64_disasm(Pointer(UInt64(@HOriginal_MessageBoxW) + offset), hs); opcodes := ''; for c := 0 to len - 1 do begin opcodes := opcodes + IntToHex(PByte(UInt64(@HOriginal_MessageBoxW) + offset + c)^, 2) + ' '; end; Memo1.Lines.Add(opcodes); offset := offset + len; end; //Memo1.Lines.Add(IntToStr( )); end; procedure TForm1.Button6Click(Sender: TObject); var hs: TDisasm; i, c, len, offset: Integer; opcodes: String; begin offset := 0; for i := 0 to 10 - 1 do begin len := hde64_disasm(Pointer(UInt64(StrToInt64(Edit1.Text)) + offset), hs); opcodes := ''; for c := 0 to len - 1 do begin opcodes := opcodes + IntToHex(PByte(UInt64(StrToInt64(Edit1.Text)) + offset + c)^, 2) + ' '; end; Memo1.Lines.Add(opcodes); offset := offset + len; end; //Memo1.Lines.Add(IntToStr( )); end; procedure TForm1.Button7Click(Sender: TObject); var pTrampoline: Pointer; begin pTrampoline := VirtualAlloc(nil, $1000, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (pTrampoline <> nil) then begin CreateTrampolineFunction(GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW'), pTrampoline); HOriginal_MessageBoxW := pTrampoline; if (@HOriginal_MessageBoxW <> nil) then begin InstallHook64(@Hook_MessageBoxW, GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')); Memo1.Lines.Add('Hook installed successfully! -- pFunction = ' + IntToHex(UInt64( GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')), 16)); end; end; end; end. unit uHook64; interface uses Windows, hde64; type TTrampoline64 = packed record asmJmpRip: Array [0..1] of Byte; // FF 25 JMP [RIP+6] asmZero32: Cardinal; // 00 00 00 00 00000000 asmAddress: UInt64; end; (* TTrampoline64 = packed record asmPushRax: Byte; // 50 push rax asmMovRax: Array [0..1] of Byte; // 48 b8 mov rax, asmAddress: UInt64; // 00 00 00 00 00 00 00 00 0x0 asmXchgRspRax: Array [0..3] of Byte; // 48 87 04 24 xchg QWORD PTR[rsp], rax asmRet: Byte; // c3 ret end; *) (* 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6] 0x0000000000000000ULL // Absolute destination address *) PTrampoline64 = ^TTrampoline64; TTrampolineCall64 = packed record asmCallRip: Array [0..1] of Byte; // FF 15 CALL [RIP+8] asmRipOffset: Cardinal; // 00 00 00 02 00000002 asmJmp10: Array [0..1] of Byte; // EB 08 JMP +10 asmAddress: UInt64; end; PTrampolineCall64 = ^TTrampolineCall64; var (* Trampoline64_DefaultValues: TTrampoline64 = ( asmPushRax: $50; asmMovRax: ($48, $B8); asmAddress: $0000000000000000; asmXchgRspRax: ($48, $87, $04, $24); asmRet: $C3; ); *) Trampoline64_DefaultValues: TTrampoline64 = ( asmJmpRip: ($FF, $25); asmZero32: $00000000; asmAddress: $0000000000000000; ); TrampolineCall64_DefaultValues: TTrampolineCall64 = ( asmCallRip: ($FF, $15); asmRipOffset: $00000002; asmJmp10: ($EB, $08); asmAddress: $0000000000000000; ); function GetMinHookLength(iLen: Cardinal; p: Pointer): Integer; function InstallHook64(pHookFunction, pFunction: Pointer): Pointer; implementation function GetMinHookLength(iLen: Cardinal; p: Pointer): Integer; var hs: TDisasm; begin Result := 0; repeat try Result := Cardinal(Result) + hde64_disasm(Pointer(UInt64(p) + Result), hs); except Result := -1; Break; end; until (Cardinal(Result) >= iLen); end; function InstallHook64(pHookFunction, pFunction: Pointer): Pointer; var iMinLen: Integer; OldProtect: Cardinal; Trampoline64_Jump, Trampoline64_ReturnOriginal: TTrampoline64; begin Result := nil; iMinLen := GetMinHookLength(SizeOf(TTrampoline64), pFunction); if (iMinLen > 0) then begin if (VirtualProtect(pFunction, iMinLen, PAGE_EXECUTE_READWRITE, OldProtect)) then begin Trampoline64_Jump := Trampoline64_DefaultValues; Trampoline64_Jump.asmAddress := UInt64(pHookFunction); // copy original instructions before overwriting it Result := VirtualAlloc(nil, iMinLen + SizeOf(TTrampoline64), MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (Result <> nil) then begin Trampoline64_ReturnOriginal := Trampoline64_DefaultValues; Trampoline64_ReturnOriginal.asmAddress := UInt64(pFunction) + iMinLen; CopyMemory(Result, pFunction, iMinLen); CopyMemory(Pointer(UInt64(Result) + iMinLen), @Trampoline64_ReturnOriginal, SizeOf(TTrampoline64)); end; CopyMemory(pFunction, @Trampoline64_Jump, SizeOf(TTrampoline64)); VirtualProtect(pFunction, iMinLen, OldProtect, OldProtect); end; end; end; end. Added the RELATIVE DIRECT CALL assembly "re-coding".
  2. oops, small fix: unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, hde64, uBytesToPascal2, uHook64; type TForm1 = class(TForm) Button1: TButton; Memo1: TMemo; Button2: TButton; Button3: TButton; Button4: TButton; Button5: TButton; Button6: TButton; Edit1: TEdit; Button7: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button4Click(Sender: TObject); procedure Button3Click(Sender: TObject); procedure Button5Click(Sender: TObject); procedure Button6Click(Sender: TObject); procedure Button7Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; HOriginal_MessageBoxW: function (p1: Int64; lpText, lpCaption: PWideChar; p4: Cardinal): Integer; stdcall = nil; implementation {$R *.dfm} function CreateTrampolineFunction(p, pTrampoline: Pointer): Boolean; var hs: TDisasm; bFinished: Boolean; opcodes: String; c: Integer; dwDisasmBytes: Cardinal; dwTotalDisasmBytes: Cardinal; pCurrentInstructionAddr: Pointer; pCopyAddress: Pointer; pCopySrc: Pointer; dwCopySize: NativeUInt; arrBuffer: Array [0..15] of Byte; pRelAddress: PCardinal; Trampoline64_ReturnOriginal: TTrampoline64; begin Result := False; bFinished := False; dwTotalDisasmBytes := 0; pCopyAddress := pTrampoline; pCopySrc := nil; dwCopySize := 0; repeat try pCurrentInstructionAddr := Pointer(UInt64(p) + dwTotalDisasmBytes); dwDisasmBytes := hde64_disasm(pCurrentInstructionAddr, hs); opcodes := ''; for c := 0 to dwDisasmBytes - 1 do begin opcodes := opcodes + IntToHex(PByte(UInt64(pCurrentInstructionAddr) + c)^, 2) + ' '; end; Form1.Memo1.Lines.Add('$' + IntToHex(UInt64(pCurrentInstructionAddr), 16) + ' len(' + IntToStr(hs.len) + ') ' + opcodes); if ((hs.flags and F_ERROR) <> 0) then begin Result := False; Break; end; pCopySrc := pCurrentInstructionAddr; dwCopySize := hs.len; if (dwTotalDisasmBytes >= SizeOf(TTrampoline64)) then begin Form1.Memo1.Lines.Add('Necessary space reached, copying jump instructions.'); Trampoline64_ReturnOriginal := Trampoline64_DefaultValues; Trampoline64_ReturnOriginal.asmAddress := UInt64(p) + dwTotalDisasmBytes; pCopySrc := @Trampoline64_ReturnOriginal; dwCopySize := SizeOf(TTrampoline64); bFinished := True; Result := True; end // Instructions using RIP relative addressing. (ModR/M = 00???101B) else if ((hs.modrm and $C7) = $05) then begin // Relative address is stored at (instruction length - immediate value length - 4). CopyMemory(@arrBuffer[0], pCurrentInstructionAddr, hs.len); pRelAddress := Pointer(UInt64(@arrBuffer[0]) + hs.len - ((hs.flags and $3C) shr 2) - 4); pRelAddress^ := Cardinal( (UInt64(pCurrentInstructionAddr) - UInt64(pCopyAddress) + hs.disp.disp32) ); pCopySrc := @arrBuffer[0]; Form1.Memo1.Lines.Add('Instruction using RIP relative addressing ($' + IntToHex(PCardinal( UInt64(pCurrentInstructionAddr) + hs.len - ((hs.flags and $3C) shr 2) - 4 )^, 8) + ').'); Form1.Memo1.Lines.Add('Flags = $' + IntToHex(((hs.flags and $3C) shr 2), 8)); //hs.len - ((hs.flags and $3C) shr 2) Form1.Memo1.Lines.Add('disp32 = $' + IntToHex(hs.disp.disp32, 8)); Form1.Memo1.Lines.Add('Address = $' + IntToHex(UInt64(pCurrentInstructionAddr) + hs.len + hs.disp.disp32, 16)); end // Direct relative CALL else if (hs.opcode = $E8) then begin Form1.Memo1.Lines.Add('Direct relative CALL.'); end // Direct relative JMP (EB or E9) else if ((hs.opcode and $FD) = $E9) then begin Form1.Memo1.Lines.Add('Direct relative JMP (EB or E9).'); end // Direct relative Jcc else if ((hs.opcode and $F0) = $70) or ((hs.opcode and $FC) = $E0) or ((hs.opcode2 and $F0) = $80) then begin Form1.Memo1.Lines.Add('Direct relative Jcc.'); end // RET (C2 or C3) else if ((hs.opcode and $FE) = $C2) then begin bFinished := True; Result := True; end; if ((pCopySrc <> nil) and (dwCopySize > 0)) then begin CopyMemory(pCopyAddress, pCopySrc, dwCopySize); pCopyAddress := Pointer(UInt64(pCopyAddress) + dwCopySize); end; dwTotalDisasmBytes := dwTotalDisasmBytes + dwDisasmBytes; except Result := False; Break; end; until (bFinished); end; function Hook_MessageBoxW(p1: Int64; lpText, lpCaption: PWideChar; p4: Cardinal): Integer; stdcall; var strText, strCaption: String; begin //Result := 0; strText := WideCharToString(lpText); strCaption := WideCharToString(lpCaption); Form1.Memo1.Lines.Add('Intercepted: ' + strText + ' - ' + strCaption); //MessageBoxA(0, PChar(strText), PChar(strCaption), MB_OK); Result := HOriginal_MessageBoxW(p1, lpText, lpCaption, p4); end; procedure Test; begin MessageBoxW(0, 'Test', 'Program', MB_OK); end; procedure TForm1.Button1Click(Sender: TObject); var hs: TDisasm; i, c, len, offset: Integer; opcodes: String; begin offset := 0; for i := 0 to 10 - 1 do begin len := hde64_disasm(Pointer(UInt64(GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')) + offset), hs); opcodes := ''; for c := 0 to len - 1 do begin opcodes := opcodes + IntToHex(PByte(UInt64(GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')) + offset + c)^, 2) + ' '; end; Memo1.Lines.Add(opcodes); offset := offset + len; end; //Memo1.Lines.Add(IntToStr( )); end; procedure TForm1.Button2Click(Sender: TObject); begin Memo1.Lines.Add(IntToStr(GetMinHookLength(16, GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')))); end; procedure TForm1.Button3Click(Sender: TObject); begin Test; end; procedure TForm1.Button4Click(Sender: TObject); begin HOriginal_MessageBoxW := InstallHook64(@Hook_MessageBoxW, GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')); if (@HOriginal_MessageBoxW <> nil) then begin Memo1.Lines.Add('Hook installed successfully! -- pFunction = ' + IntToHex(UInt64( GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')), 16)); end; end; procedure TForm1.Button5Click(Sender: TObject); var hs: TDisasm; i, c, len, offset: Integer; opcodes: String; begin offset := 0; for i := 0 to 10 - 1 do begin len := hde64_disasm(Pointer(UInt64(@HOriginal_MessageBoxW) + offset), hs); opcodes := ''; for c := 0 to len - 1 do begin opcodes := opcodes + IntToHex(PByte(UInt64(@HOriginal_MessageBoxW) + offset + c)^, 2) + ' '; end; Memo1.Lines.Add(opcodes); offset := offset + len; end; //Memo1.Lines.Add(IntToStr( )); end; procedure TForm1.Button6Click(Sender: TObject); var hs: TDisasm; i, c, len, offset: Integer; opcodes: String; begin offset := 0; for i := 0 to 10 - 1 do begin len := hde64_disasm(Pointer(UInt64(StrToInt64(Edit1.Text)) + offset), hs); opcodes := ''; for c := 0 to len - 1 do begin opcodes := opcodes + IntToHex(PByte(UInt64(StrToInt64(Edit1.Text)) + offset + c)^, 2) + ' '; end; Memo1.Lines.Add(opcodes); offset := offset + len; end; //Memo1.Lines.Add(IntToStr( )); end; procedure TForm1.Button7Click(Sender: TObject); var pTrampoline: Pointer; begin pTrampoline := VirtualAlloc(nil, $1000, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (pTrampoline <> nil) then begin CreateTrampolineFunction(GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW'), pTrampoline); HOriginal_MessageBoxW := pTrampoline; if (@HOriginal_MessageBoxW <> nil) then begin InstallHook64(@Hook_MessageBoxW, GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')); Memo1.Lines.Add('Hook installed successfully! -- pFunction = ' + IntToHex(UInt64( GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')), 16)); end; end; end; end.
  3. Nice and cozy, RIP relative addressing working. unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, hde64, uBytesToPascal2, uHook64; type TForm1 = class(TForm) Button1: TButton; Memo1: TMemo; Button2: TButton; Button3: TButton; Button4: TButton; Button5: TButton; Button6: TButton; Edit1: TEdit; Button7: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button4Click(Sender: TObject); procedure Button3Click(Sender: TObject); procedure Button5Click(Sender: TObject); procedure Button6Click(Sender: TObject); procedure Button7Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; HOriginal_MessageBoxW: function (p1: Int64; lpText, lpCaption: PWideChar; p4: Cardinal): Integer; stdcall = nil; implementation {$R *.dfm} function CreateTrampolineFunction(p, pTrampoline: Pointer): Boolean; var hs: TDisasm; bFinished: Boolean; opcodes: String; c: Integer; dwDisasmBytes: Cardinal; dwTotalDisasmBytes: Cardinal; pCurrentInstructionAddr: Pointer; pCopyAddress: Pointer; pCopySrc: Pointer; dwCopySize: NativeUInt; arrBuffer: Array [0..15] of Byte; pRelAddress: PCardinal; Trampoline64_ReturnOriginal: TTrampoline64; begin Result := False; bFinished := False; dwTotalDisasmBytes := 0; pCopyAddress := pTrampoline; pCopySrc := nil; dwCopySize := 0; repeat try pCurrentInstructionAddr := Pointer(UInt64(p) + dwTotalDisasmBytes); dwDisasmBytes := hde64_disasm(pCurrentInstructionAddr, hs); dwTotalDisasmBytes := dwTotalDisasmBytes + dwDisasmBytes; opcodes := ''; for c := 0 to dwDisasmBytes - 1 do begin opcodes := opcodes + IntToHex(PByte(UInt64(pCurrentInstructionAddr) + c)^, 2) + ' '; end; Form1.Memo1.Lines.Add('$' + IntToHex(UInt64(pCurrentInstructionAddr), 16) + ' len(' + IntToStr(hs.len) + ') ' + opcodes); if ((hs.flags and F_ERROR) <> 0) then begin Result := False; Break; end; pCopySrc := pCurrentInstructionAddr; dwCopySize := hs.len; if (dwTotalDisasmBytes >= SizeOf(TTrampoline64)) then begin Form1.Memo1.Lines.Add('Necessary space reached, copying jump instructions.'); Trampoline64_ReturnOriginal := Trampoline64_DefaultValues; Trampoline64_ReturnOriginal.asmAddress := UInt64(p) + dwTotalDisasmBytes; pCopySrc := @Trampoline64_ReturnOriginal; dwCopySize := SizeOf(TTrampoline64); bFinished := True; end // Instructions using RIP relative addressing. (ModR/M = 00???101B) else if ((hs.modrm and $C7) = $05) then begin // Relative address is stored at (instruction length - immediate value length - 4). CopyMemory(@arrBuffer[0], pCurrentInstructionAddr, hs.len); pRelAddress := Pointer(UInt64(@arrBuffer[0]) + hs.len - ((hs.flags and $3C) shr 2) - 4); pRelAddress^ := Cardinal( (UInt64(pCurrentInstructionAddr) + hs.len + hs.disp.disp32) - (UInt64(pCopyAddress) + hs.len) ); pCopySrc := @arrBuffer[0]; Form1.Memo1.Lines.Add('Instruction using RIP relative addressing ($' + IntToHex(PCardinal( UInt64(pCurrentInstructionAddr) + hs.len - ((hs.flags and $3C) shr 2) - 4 )^, 8) + ').'); Form1.Memo1.Lines.Add('Flags = $' + IntToHex(((hs.flags and $3C) shr 2), 8)); //hs.len - ((hs.flags and $3C) shr 2) Form1.Memo1.Lines.Add('disp32 = $' + IntToHex(hs.disp.disp32, 8)); Form1.Memo1.Lines.Add('Address = $' + IntToHex(UInt64(pCurrentInstructionAddr) + hs.len + hs.disp.disp32, 16)); end // Direct relative CALL else if (hs.opcode = $E8) then begin Form1.Memo1.Lines.Add('Direct relative CALL.'); end // Direct relative JMP (EB or E9) else if ((hs.opcode and $FD) = $E9) then begin Form1.Memo1.Lines.Add('Direct relative JMP (EB or E9).'); end // Direct relative Jcc else if ((hs.opcode and $F0) = $70) or ((hs.opcode and $FC) = $E0) or ((hs.opcode2 and $F0) = $80) then begin Form1.Memo1.Lines.Add('Direct relative Jcc.'); end // RET (C2 or C3) else if ((hs.opcode and $FE) = $C2) then begin bFinished := True; Result := True; end; if ((pCopySrc <> nil) and (dwCopySize > 0)) then begin CopyMemory(pCopyAddress, pCopySrc, dwCopySize); pCopyAddress := Pointer(UInt64(pCopyAddress) + dwCopySize); end; except Result := False; Break; end; until (bFinished); end; function Hook_MessageBoxW(p1: Int64; lpText, lpCaption: PWideChar; p4: Cardinal): Integer; stdcall; var strText, strCaption: String; begin //Result := 0; strText := WideCharToString(lpText); strCaption := WideCharToString(lpCaption); Form1.Memo1.Lines.Add('Intercepted: ' + strText + ' - ' + strCaption); //MessageBoxA(0, PChar(strText), PChar(strCaption), MB_OK); Result := HOriginal_MessageBoxW(p1, lpText, lpCaption, p4); end; procedure Test; begin MessageBoxW(0, 'Test', 'Program', MB_OK); end; procedure TForm1.Button1Click(Sender: TObject); var hs: TDisasm; i, c, len, offset: Integer; opcodes: String; begin offset := 0; for i := 0 to 10 - 1 do begin len := hde64_disasm(Pointer(UInt64(GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')) + offset), hs); opcodes := ''; for c := 0 to len - 1 do begin opcodes := opcodes + IntToHex(PByte(UInt64(GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')) + offset + c)^, 2) + ' '; end; Memo1.Lines.Add(opcodes); offset := offset + len; end; //Memo1.Lines.Add(IntToStr( )); end; procedure TForm1.Button2Click(Sender: TObject); begin Memo1.Lines.Add(IntToStr(GetMinHookLength(16, GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')))); end; procedure TForm1.Button3Click(Sender: TObject); begin Test; end; procedure TForm1.Button4Click(Sender: TObject); begin HOriginal_MessageBoxW := InstallHook64(@Hook_MessageBoxW, GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')); if (@HOriginal_MessageBoxW <> nil) then begin Memo1.Lines.Add('Hook installed successfully! -- pFunction = ' + IntToHex(UInt64( GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')), 16)); end; end; procedure TForm1.Button5Click(Sender: TObject); var hs: TDisasm; i, c, len, offset: Integer; opcodes: String; begin offset := 0; for i := 0 to 10 - 1 do begin len := hde64_disasm(Pointer(UInt64(@HOriginal_MessageBoxW) + offset), hs); opcodes := ''; for c := 0 to len - 1 do begin opcodes := opcodes + IntToHex(PByte(UInt64(@HOriginal_MessageBoxW) + offset + c)^, 2) + ' '; end; Memo1.Lines.Add(opcodes); offset := offset + len; end; //Memo1.Lines.Add(IntToStr( )); end; procedure TForm1.Button6Click(Sender: TObject); var hs: TDisasm; i, c, len, offset: Integer; opcodes: String; begin offset := 0; for i := 0 to 10 - 1 do begin len := hde64_disasm(Pointer(UInt64(StrToInt64(Edit1.Text)) + offset), hs); opcodes := ''; for c := 0 to len - 1 do begin opcodes := opcodes + IntToHex(PByte(UInt64(StrToInt64(Edit1.Text)) + offset + c)^, 2) + ' '; end; Memo1.Lines.Add(opcodes); offset := offset + len; end; //Memo1.Lines.Add(IntToStr( )); end; procedure TForm1.Button7Click(Sender: TObject); var pTrampoline: Pointer; begin pTrampoline := VirtualAlloc(nil, $1000, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (pTrampoline <> nil) then begin CreateTrampolineFunction(GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW'), pTrampoline); HOriginal_MessageBoxW := pTrampoline; if (@HOriginal_MessageBoxW <> nil) then begin InstallHook64(@Hook_MessageBoxW, GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')); Memo1.Lines.Add('Hook installed successfully! -- pFunction = ' + IntToHex(UInt64( GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')), 16)); end; end; end; end. Tested only with MessageBoxW because jumps and calls are not implemented yet. Using the JMP [RIP+6] followed by the absolute address and method to jump, only needs 14 bytes. type TTrampoline64 = packed record asmJmpRip: Array [0..1] of Byte; // FF 25 JMP [RIP+6] asmZero32: Cardinal; // 00 00 00 00 00000000 asmAddress: UInt64; end; (* TTrampoline64 = packed record asmPushRax: Byte; // 50 push rax asmMovRax: Array [0..1] of Byte; // 48 b8 mov rax, asmAddress: UInt64; // 00 00 00 00 00 00 00 00 0x0 asmXchgRspRax: Array [0..3] of Byte; // 48 87 04 24 xchg QWORD PTR[rsp], rax asmRet: Byte; // c3 ret end; *) (* 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6] 0x0000000000000000ULL // Absolute destination address *) PTrampoline64 = ^TTrampoline64; var (* Trampoline64_DefaultValues: TTrampoline64 = ( asmPushRax: $50; asmMovRax: ($48, $B8); asmAddress: $0000000000000000; asmXchgRspRax: ($48, $87, $04, $24); asmRet: $C3; ); *) Trampoline64_DefaultValues: TTrampoline64 = ( asmJmpRip: ($FF, $25); asmZero32: $00000000; asmAddress: $0000000000000000; ); Next I will finish the implementation of the other address relative instructions (jmp, jcc, call) and I will implement the same Allocation method used by MinHook on buffer.c. hook is going well and it seems to be a solved issue, just a matter of time until I have everything ported to delphi.
  4. Important to fix a big mistake I made at converting the hde64 structure. I fuck.ed things up translating unions to Delphi... (* * Hacker Disassembler Engine 64 * Copyright (c) 2006-2009, Veacheslav Patkov * aLL rights reserved. * * hde64.pas : pascal header file (Free pascal, Delphi) * *) unit hde64; interface const F_MODRM = $00000001; F_SIB = $00000002; F_IMM8 = $00000004; F_IMM16 = $00000008; F_IMM32 = $00000010; F_IMM64 = $00000020; F_DISP8 = $00000040; F_DISP16 = $00000080; F_DISP32 = $00000100; F_RELATIVE = $00000200; F_ERROR = $00001000; F_ERROR_OPCODE = $00002000; F_ERROR_LENGTH = $00004000; F_ERROR_LOCK = $00008000; F_ERROR_OPERAND = $00010000; F_PREFIX_REPNZ = $01000000; F_PREFIX_REPX = $02000000; F_PREFIX_REP = $03000000; F_PREFIX_66 = $04000000; F_PREFIX_67 = $08000000; F_PREFIX_LOCK = $10000000; F_PREFIX_SEG = $20000000; F_PREFIX_REX = $40000000; F_PREFIX_ANY = $7f000000; PREFIX_SEGMENT_CS = $2e; PREFIX_SEGMENT_SS = $36; PREFIX_SEGMENT_DS = $3e; PREFIX_SEGMENT_ES = $26; PREFIX_SEGMENT_FS = $64; PREFIX_SEGMENT_GS = $65; PREFIX_LOCK = $f0; PREFIX_REPNZ = $f2; PREFIX_REPX = $f3; PREFIX_OPERAND_SIZE = $66; PREFIX_ADDRESS_SIZE = $67; type TImm = packed record case integer of 0: (imm8 : byte;); { immediate value imm8 } 1: (imm16 : word;); { immediate value imm16 } 2: (imm32 : cardinal;); { immediate value imm32 } 3: (imm64 : uint64;); { immediate value imm64 } end; TDisp = packed record case integer of 0: (disp8 : byte;); { displacement disp8 } 1: (disp16 : word;); { displacement disp16 } 2: (disp32 : cardinal;); { displacement disp32 } end; TDisasm = packed record len : byte; { length of command } p_rep : byte; { rep/repz (0xf3) & repnz (0xf2) prefix } p_lock : byte; { lock prefix: 0xf0 } p_seg : byte; { segment prefix: 0x2e,0x36,0x3e,0x26,0x64,0x65 } p_66 : byte; { operand-size override prefix: 0x66 } p_67 : byte; { address-size override prefix: 0x67 } rex : byte; rex_w : byte; rex_r : byte; rex_x : byte; rex_b : byte; opcode : byte; { opcode } opcode2 : byte; { second opcode (if first opcode is 0x0f) } modrm : byte; { ModR/M byte } modrm_mod : byte; { mod field of ModR/M } modrm_reg : byte; { reg field of ModR/M } modrm_rm : byte; { r/m field of ModR/M } sib : byte; { SIB byte } sib_scale : byte; { scale field of SIB } sib_index : byte; { index field of SIB } sib_base : byte; { base field of SIB } imm : TImm; disp : TDisp; flags : cardinal; { flags } end; function hde64_disasm(code: pointer; var hs: TDisasm): cardinal; cdecl; implementation {$LINK 'hde64.obj'} function hde64_disasm(code: pointer; var hs: TDisasm): cardinal; cdecl; external; end. $0000000077421360 len(4) 48 83 EC 38 $0000000077421364 len(3) 45 33 DB $0000000077421367 len(7) 44 39 1D CE 0D 02 00 Instruction using RIP relative addressing ($00020DCE). Flags = $00000000 disp32 = $00020DCE Address = $000000007744213C $000000007742136E len(2) 74 2E Direct relative Jcc. $0000000077421370 len(9) 65 48 8B 04 25 30 00 00 00 $0000000077421379 len(4) 4C 8B 50 48 $000000007742137D len(2) 33 C0 $000000007742137F len(9) F0 4C 0F B1 15 A8 26 02 00 Instruction using RIP relative addressing ($000226A8). Flags = $00000000 disp32 = $000226A8 Address = $0000000077443A30 $0000000077421388 len(7) 4C 8B 15 99 26 02 00 Instruction using RIP relative addressing ($00022699). Flags = $00000000 disp32 = $00022699 Address = $0000000077443A28 $000000007742138F len(4) 41 8D 43 01 $0000000077421393 len(4) 4C 0F 44 D0 $0000000077421397 len(7) 4C 89 15 8A 26 02 00 Instruction using RIP relative addressing ($0002268A). Flags = $00000000 disp32 = $0002268A Address = $0000000077443A28 $000000007742139E len(5) 83 4C 24 28 FF $00000000774213A3 len(6) 66 44 89 5C 24 20 $00000000774213A9 len(5) E8 56 00 00 00 Direct relative CALL. $00000000774213AE len(4) 48 83 C4 38 $00000000774213B2 len(1) C3 unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, hde64, uBytesToPascal2, uHook64; type TForm1 = class(TForm) Button1: TButton; Memo1: TMemo; Button2: TButton; Button3: TButton; Button4: TButton; Button5: TButton; Button6: TButton; Edit1: TEdit; Button7: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button4Click(Sender: TObject); procedure Button3Click(Sender: TObject); procedure Button5Click(Sender: TObject); procedure Button6Click(Sender: TObject); procedure Button7Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; HOriginal_MessageBoxW: function (p1: Int64; lpText, lpCaption: PWideChar; p4: Cardinal): Integer; stdcall = nil; implementation {$R *.dfm} function CreateTrampolineFunction(p: Pointer): Boolean; var hs: TDisasm; bFinished: Boolean; opcodes: String; c: Integer; dwDisasmBytes: Cardinal; dwTotalDisasmBytes: Cardinal; pCurrentInstructionAddr: Pointer; begin Result := False; bFinished := False; dwTotalDisasmBytes := 0; repeat try pCurrentInstructionAddr := Pointer(UInt64(p) + dwTotalDisasmBytes); dwDisasmBytes := hde64_disasm(pCurrentInstructionAddr, hs); dwTotalDisasmBytes := dwTotalDisasmBytes + dwDisasmBytes; opcodes := ''; for c := 0 to dwDisasmBytes - 1 do begin opcodes := opcodes + IntToHex(PByte(UInt64(pCurrentInstructionAddr) + c)^, 2) + ' '; end; Form1.Memo1.Lines.Add('$' + IntToHex(UInt64(pCurrentInstructionAddr), 16) + ' len(' + IntToStr(hs.len) + ') ' + opcodes); if ((hs.flags and F_ERROR) <> 0) then begin Result := False; Break; end; // Instructions using RIP relative addressing. (ModR/M = 00???101B) if ((hs.modrm and $C7) = $05) then begin // Relative address is stored at (instruction length - immediate value length - 4). Form1.Memo1.Lines.Add('Instruction using RIP relative addressing ($' + IntToHex(PCardinal( UInt64(pCurrentInstructionAddr) + hs.len - ((hs.flags and $3C) shr 2) - 4 )^, 8) + ').'); Form1.Memo1.Lines.Add('Flags = $' + IntToHex(((hs.flags and $3C) shr 2), 8)); //hs.len - ((hs.flags and $3C) shr 2) Form1.Memo1.Lines.Add('disp32 = $' + IntToHex(hs.disp.disp32, 8)); Form1.Memo1.Lines.Add('Address = $' + IntToHex(UInt64(pCurrentInstructionAddr) + hs.len + hs.disp.disp32, 16)); end // Direct relative CALL else if (hs.opcode = $E8) then begin Form1.Memo1.Lines.Add('Direct relative CALL.'); end // Direct relative JMP (EB or E9) else if ((hs.opcode and $FD) = $E9) then begin Form1.Memo1.Lines.Add('Direct relative JMP (EB or E9).'); end // Direct relative Jcc else if ((hs.opcode and $F0) = $70) or ((hs.opcode and $FC) = $E0) or ((hs.opcode2 and $F0) = $80) then begin Form1.Memo1.Lines.Add('Direct relative Jcc.'); end // RET (C2 or C3) else if ((hs.opcode and $FE) = $C2) then begin bFinished := True; Result := True; end; except Result := False; Break; end; until (bFinished); end; function Hook_MessageBoxW(p1: Int64; lpText, lpCaption: PWideChar; p4: Cardinal): Integer; stdcall; var strText, strCaption: String; begin Result := 0; strText := WideCharToString(lpText); strCaption := WideCharToString(lpCaption); Form1.Memo1.Lines.Add('Intercepted: ' + strText + ' - ' + strCaption); //MessageBoxA(0, PChar(strText), PChar(strCaption), MB_OK); //Result := HOriginal_MessageBoxW(p1, lpText, lpCaption, p4); end; procedure Test; begin MessageBoxW(0, 'Test', 'Program', MB_OK); end; procedure TForm1.Button1Click(Sender: TObject); var hs: TDisasm; i, c, len, offset: Integer; opcodes: String; begin offset := 0; for i := 0 to 10 - 1 do begin len := hde64_disasm(Pointer(UInt64(GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')) + offset), hs); opcodes := ''; for c := 0 to len - 1 do begin opcodes := opcodes + IntToHex(PByte(UInt64(GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')) + offset + c)^, 2) + ' '; end; Memo1.Lines.Add(opcodes); offset := offset + len; end; //Memo1.Lines.Add(IntToStr( )); end; procedure TForm1.Button2Click(Sender: TObject); begin Memo1.Lines.Add(IntToStr(GetMinHookLength(16, GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')))); end; procedure TForm1.Button3Click(Sender: TObject); begin Test; end; procedure TForm1.Button4Click(Sender: TObject); begin HOriginal_MessageBoxW := InstallHook64(@Hook_MessageBoxW, GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')); if (@HOriginal_MessageBoxW <> nil) then begin Memo1.Lines.Add('Hook installed successfully! -- pFunction = ' + IntToHex(UInt64( GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')), 16)); end; end; procedure TForm1.Button5Click(Sender: TObject); var hs: TDisasm; i, c, len, offset: Integer; opcodes: String; begin offset := 0; for i := 0 to 10 - 1 do begin len := hde64_disasm(Pointer(UInt64(@HOriginal_MessageBoxW) + offset), hs); opcodes := ''; for c := 0 to len - 1 do begin opcodes := opcodes + IntToHex(PByte(UInt64(@HOriginal_MessageBoxW) + offset + c)^, 2) + ' '; end; Memo1.Lines.Add(opcodes); offset := offset + len; end; //Memo1.Lines.Add(IntToStr( )); end; procedure TForm1.Button6Click(Sender: TObject); var hs: TDisasm; i, c, len, offset: Integer; opcodes: String; begin offset := 0; for i := 0 to 10 - 1 do begin len := hde64_disasm(Pointer(UInt64(StrToInt64(Edit1.Text)) + offset), hs); opcodes := ''; for c := 0 to len - 1 do begin opcodes := opcodes + IntToHex(PByte(UInt64(StrToInt64(Edit1.Text)) + offset + c)^, 2) + ' '; end; Memo1.Lines.Add(opcodes); offset := offset + len; end; //Memo1.Lines.Add(IntToStr( )); end; procedure TForm1.Button7Click(Sender: TObject); begin CreateTrampolineFunction(GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')); end; end. So now we know where the RIP relative address is at the instruction, and to where it points. When copying to our own trampoline function we will relocate it based on our new location, that should be the (instructionAddress + instructionLength + disp32) - (New_instructionAddress + instructionLength)
  5. Maybe gbuster is rewriting the hook over and over again?
  6. of course that for this to work it is only necessary to relocate the addresses that are in the range occupied by the trampoline to the interception function.. that is something like 16 or 14 bytes depending on what method is used. it is possible to make a JMP [RIP+6] followed by the absolute address. This only consumes 14 bytes, so I will probably be using this... Besides that I am thinking about creating a "emulation" function just to map the entire function... with its branches and stuff. Not following the calls but following the jumps and stopping on ret. That would be interesting and maybe it would be possible to relocate entire functions out of its original location. That is just an idea.
  7. .text:0000000078C91360 ; =============== S U B R O U T I N E ======================================= .text:0000000078C91360 .text:0000000078C91360 .text:0000000078C91360 public MessageBoxW .text:0000000078C91360 MessageBoxW proc near ; CODE XREF: sub_78C703F4+57�p .text:0000000078C91360 ; DATA XREF: .rdata:off_78CA33A8�o .text:0000000078C91360 .text:0000000078C91360 var_18 = word ptr -18h .text:0000000078C91360 var_10 = dword ptr -10h .text:0000000078C91360 .text:0000000078C91360 sub rsp, 38h len(4) 48 83 EC 38 .text:0000000078C91364 xor r11d, r11d len(3) 45 33 DB .text:0000000078C91367 cmp cs:dword_78CB213C, r11d len(7) 44 39 1D CE 0D 02 00 (Instruction using RIP relative addressing.) .text:0000000078C9136E jz short loc_78C9139E len(2) 74 2E (Direct relative Jcc) .text:0000000078C91370 mov rax, gs:30h len(9) 65 48 8B 04 25 30 00 00 00 .text:0000000078C91379 mov r10, [rax+48h] len(4) 4C 8B 50 48 .text:0000000078C9137D xor eax, eax len(2) 33 C0 .text:0000000078C9137F lock cmpxchg cs:qword_78CB3A30, r10 len(9) F0 4C 0F B1 15 A8 26 02 00 (Instruction using RIP relative addressing.) .text:0000000078C91388 mov r10, cs:qword_78CB3A28 len(7) 4C 8B 15 99 26 02 00 (Instruction using RIP relative addressing.) .text:0000000078C9138F lea eax, [r11+1] len(4) 41 8D 43 01 .text:0000000078C91393 cmovz r10, rax len(4) 4C 0F 44 D0 .text:0000000078C91397 mov cs:qword_78CB3A28, r10 len(7) 4C 89 15 8A 26 02 00 (Instruction using RIP relative addressing.) .text:0000000078C9139E .text:0000000078C9139E loc_78C9139E: ; CODE XREF: MessageBoxW+E�j .text:0000000078C9139E or [rsp+38h+var_10], 0FFFFFFFFh len(5) 83 4C 24 28 FF .text:0000000078C913A3 mov [rsp+38h+var_18], r11w len(6) 66 44 89 5C 24 20 .text:0000000078C913A9 call MessageBoxTimeoutW len(5) E8 56 00 00 00 (Direct relative CALL.) .text:0000000078C913AE add rsp, 38h 48 83 C4 38 .text:0000000078C913B2 retn len(1) C3 .text:0000000078C913B2 ; ---------------------------------------------------------------------------
  8. Slowly progressing len(4) 48 83 EC 38 len(3) 45 33 DB len(7) 44 39 1D CE 0D 02 00 Instruction using RIP relative addressing. len(2) 74 2E Direct relative Jcc len(9) 65 48 8B 04 25 30 00 00 00 len(4) 4C 8B 50 48 len(2) 33 C0 len(9) F0 4C 0F B1 15 A8 26 02 00 Instruction using RIP relative addressing. len(7) 4C 8B 15 99 26 02 00 Instruction using RIP relative addressing. len(4) 41 8D 43 01 len(4) 4C 0F 44 D0 len(7) 4C 89 15 8A 26 02 00 Instruction using RIP relative addressing. len(5) 83 4C 24 28 FF len(6) 66 44 89 5C 24 20 len(5) E8 56 00 00 00 Direct relative CALL len(4) 48 83 C4 38 len(1) C3 unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, hde64, uBytesToPascal2, uHook64; type TForm1 = class(TForm) Button1: TButton; Memo1: TMemo; Button2: TButton; Button3: TButton; Button4: TButton; Button5: TButton; Button6: TButton; Edit1: TEdit; Button7: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button4Click(Sender: TObject); procedure Button3Click(Sender: TObject); procedure Button5Click(Sender: TObject); procedure Button6Click(Sender: TObject); procedure Button7Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; HOriginal_MessageBoxW: function (p1: Int64; lpText, lpCaption: PWideChar; p4: Cardinal): Integer; stdcall = nil; implementation {$R *.dfm} function CreateTrampolineFunction(p: Pointer): Boolean; var hs: TDisasm; bFinished: Boolean; opcodes: String; c: Integer; dwDisasmBytes: Cardinal; dwTotalDisasmBytes: Cardinal; begin Result := False; bFinished := False; dwTotalDisasmBytes := 0; repeat try dwDisasmBytes := hde64_disasm(Pointer(UInt64(p) + dwTotalDisasmBytes), hs); opcodes := ''; for c := 0 to dwDisasmBytes - 1 do begin opcodes := opcodes + IntToHex(PByte(UInt64(p) + dwTotalDisasmBytes + c)^, 2) + ' '; end; Form1.Memo1.Lines.Add('len(' + IntToStr(hs.len) + ') ' + opcodes); dwTotalDisasmBytes := dwTotalDisasmBytes + dwDisasmBytes; if ((hs.flags and F_ERROR) <> 0) then begin Result := False; Break; end; // Instructions using RIP relative addressing. (ModR/M = 00???101B) if ((hs.modrm and $C7) = $05) then begin Form1.Memo1.Lines.Add('Instruction using RIP relative addressing.'); end // Direct relative CALL else if (hs.opcode = $E8) then begin Form1.Memo1.Lines.Add('Direct relative CALL'); end // Direct relative JMP (EB or E9) else if ((hs.opcode and $FD) = $E9) then begin Form1.Memo1.Lines.Add('Direct relative JMP (EB or E9)'); end // Direct relative Jcc else if ((hs.opcode and $F0) = $70) or ((hs.opcode and $FC) = $E0) or ((hs.opcode2 and $F0) = $80) then begin Form1.Memo1.Lines.Add('Direct relative Jcc'); end else if ((hs.opcode and $FE) = $C2) then begin bFinished := True; Result := True; end; except Result := False; Break; end; until (bFinished); end; function Hook_MessageBoxW(p1: Int64; lpText, lpCaption: PWideChar; p4: Cardinal): Integer; stdcall; var strText, strCaption: String; begin Result := 0; strText := WideCharToString(lpText); strCaption := WideCharToString(lpCaption); Form1.Memo1.Lines.Add('Intercepted: ' + strText + ' - ' + strCaption); //MessageBoxA(0, PChar(strText), PChar(strCaption), MB_OK); //Result := HOriginal_MessageBoxW(p1, lpText, lpCaption, p4); end; procedure Test; begin MessageBoxW(0, 'Test', 'Program', MB_OK); end; procedure TForm1.Button1Click(Sender: TObject); var hs: TDisasm; i, c, len, offset: Integer; opcodes: String; begin offset := 0; for i := 0 to 10 - 1 do begin len := hde64_disasm(Pointer(UInt64(GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')) + offset), hs); opcodes := ''; for c := 0 to len - 1 do begin opcodes := opcodes + IntToHex(PByte(UInt64(GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')) + offset + c)^, 2) + ' '; end; Memo1.Lines.Add(opcodes); offset := offset + len; end; //Memo1.Lines.Add(IntToStr( )); end; procedure TForm1.Button2Click(Sender: TObject); begin Memo1.Lines.Add(IntToStr(GetMinHookLength(16, GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')))); end; procedure TForm1.Button3Click(Sender: TObject); begin Test; end; procedure TForm1.Button4Click(Sender: TObject); begin HOriginal_MessageBoxW := InstallHook64(@Hook_MessageBoxW, GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')); if (@HOriginal_MessageBoxW <> nil) then begin Memo1.Lines.Add('Hook installed successfully! -- pFunction = ' + IntToHex(UInt64( GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')), 16)); end; end; procedure TForm1.Button5Click(Sender: TObject); var hs: TDisasm; i, c, len, offset: Integer; opcodes: String; begin offset := 0; for i := 0 to 10 - 1 do begin len := hde64_disasm(Pointer(UInt64(@HOriginal_MessageBoxW) + offset), hs); opcodes := ''; for c := 0 to len - 1 do begin opcodes := opcodes + IntToHex(PByte(UInt64(@HOriginal_MessageBoxW) + offset + c)^, 2) + ' '; end; Memo1.Lines.Add(opcodes); offset := offset + len; end; //Memo1.Lines.Add(IntToStr( )); end; procedure TForm1.Button6Click(Sender: TObject); var hs: TDisasm; i, c, len, offset: Integer; opcodes: String; begin offset := 0; for i := 0 to 10 - 1 do begin len := hde64_disasm(Pointer(UInt64(StrToInt64(Edit1.Text)) + offset), hs); opcodes := ''; for c := 0 to len - 1 do begin opcodes := opcodes + IntToHex(PByte(UInt64(StrToInt64(Edit1.Text)) + offset + c)^, 2) + ' '; end; Memo1.Lines.Add(opcodes); offset := offset + len; end; //Memo1.Lines.Add(IntToStr( )); end; procedure TForm1.Button7Click(Sender: TObject); begin CreateTrampolineFunction(GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')); end; end. (* * Hacker Disassembler Engine 64 * Copyright (c) 2006-2009, Veacheslav Patkov * aLL rights reserved. * * hde64.pas : pascal header file (Free pascal, Delphi) * *) unit hde64; interface uses Windows; const F_MODRM = $00000001; F_SIB = $00000002; F_IMM8 = $00000004; F_IMM16 = $00000008; F_IMM32 = $00000010; F_IMM64 = $00000020; F_DISP8 = $00000040; F_DISP16 = $00000080; F_DISP32 = $00000100; F_RELATIVE = $00000200; F_ERROR = $00001000; F_ERROR_OPCODE = $00002000; F_ERROR_LENGTH = $00004000; F_ERROR_LOCK = $00008000; F_ERROR_OPERAND = $00010000; F_PREFIX_REPNZ = $01000000; F_PREFIX_REPX = $02000000; F_PREFIX_REP = $03000000; F_PREFIX_66 = $04000000; F_PREFIX_67 = $08000000; F_PREFIX_LOCK = $10000000; F_PREFIX_SEG = $20000000; F_PREFIX_REX = $40000000; F_PREFIX_ANY = $7f000000; PREFIX_SEGMENT_CS = $2e; PREFIX_SEGMENT_SS = $36; PREFIX_SEGMENT_DS = $3e; PREFIX_SEGMENT_ES = $26; PREFIX_SEGMENT_FS = $64; PREFIX_SEGMENT_GS = $65; PREFIX_LOCK = $f0; PREFIX_REPNZ = $f2; PREFIX_REPX = $f3; PREFIX_OPERAND_SIZE = $66; PREFIX_ADDRESS_SIZE = $67; type TDisasm = packed record len : byte; { length of command } p_rep : byte; { rep/repz (0xf3) & repnz (0xf2) prefix } p_lock : byte; { lock prefix: 0xf0 } p_seg : byte; { segment prefix: 0x2e,0x36,0x3e,0x26,0x64,0x65 } p_66 : byte; { operand-size override prefix: 0x66 } p_67 : byte; { address-size override prefix: 0x67 } rex : byte; rex_w : byte; rex_r : byte; rex_x : byte; rex_b : byte; opcode : byte; { opcode } opcode2 : byte; { second opcode (if first opcode is 0x0f) } modrm : byte; { ModR/M byte } modrm_mod : byte; { mod field of ModR/M } modrm_reg : byte; { reg field of ModR/M } modrm_rm : byte; { r/m field of ModR/M } sib : byte; { SIB byte } sib_scale : byte; { scale field of SIB } sib_index : byte; { index field of SIB } sib_base : byte; { base field of SIB } imm8 : byte; { immediate value imm8 } imm16 : word; { immediate value imm16 } imm32 : dword; { immediate value imm32 } imm64 : dword64; { immediate value imm32 } disp8 : byte; { displacement disp8 } disp16 : word; { displacement disp16 } disp32 : dword; { displacement disp32 } flags : dword; { displacement disp32 } end; function hde64_disasm(code: pointer; var hs: TDisasm): dword; cdecl; implementation {$LINK 'hde64.obj'} function hde64_disasm(code: pointer; var hs: TDisasm): dword; cdecl; external; end.
  9. I realized there is a fucnking huge problem with hooking in win64... The API functions have execution flow and rip relative addresses right at the beginning... That makes it a lot more difficult to overwrite the original instructions and copy them elsewhere because they dont work elsewhere.. They are dependent of the address where they belong. I downloaded minhook to se how they fiz this problem and apparently they relocate the jcc, rip relative addresses and calls to the new address where they will reside. I didnt fully look into the code but that is what seems they do and that makes sense... So yeah there will be a lot of work ahead to make this to work universally. But I will because that is important to me $$ I hope minhook has done all the job so I will only rip the idea
  10. Basic functionality working. Not saving the original function yet. Have to copy the overwritten bytes to a new Allocated location to be able to use the original function. That is very important when intercepting messages that you don't want to change the functionality of the original program like ssl_write. It is possible that some programs won't allow to use VirtualAlloc with EXECUTE permissions. That is something new on win8 onwards. Of course that will also make impossible to inject dll directly from memory in code injection style, so maybe we need to create a code cave with empty space on our dll code section. But that is something I will not worry right now. Next step is to implement the original function as result for the InstallHook function. unit uHook64; interface uses Windows, hde64; type TTrampoline64 = packed record asmPushRax: Byte; // 50 push rax asmMovRax: Array [0..1] of Byte; // 48 b8 mov rax, asmAddress: UInt64; // 00 00 00 00 00 00 00 00 0x0 asmXchgRspRax: Array [0..3] of Byte; // 48 87 04 24 xchg QWORD PTR[rsp], rax asmRet: Byte; // c3 ret end; PTrampoline64 = ^TTrampoline64; var Trampoline64_DefaultValues: TTrampoline64 = ( asmPushRax: $50; asmMovRax: ($48, $B8); asmAddress: $0000000000000000; asmXchgRspRax: ($48, $87, $04, $24); asmRet: $C3; ); function GetMinHookLength(iLen: Cardinal; p: Pointer): Integer; function InstallHook64(pHookFunction, pFunction: Pointer): Pointer; implementation function GetMinHookLength(iLen: Cardinal; p: Pointer): Integer; var hs: TDisasm; begin Result := 0; repeat try Result := Cardinal(Result) + hde64_disasm(Pointer(UInt64(p) + Result), hs); except Result := -1; Break; end; until (Cardinal(Result) >= iLen); end; function InstallHook64(pHookFunction, pFunction: Pointer): Pointer; var iMinLen: Integer; OldProtect: Cardinal; Trampoline64_Jump: TTrampoline64; begin Result := nil; iMinLen := GetMinHookLength(SizeOf(TTrampoline64), pFunction); if (iMinLen > 0) then begin if (VirtualProtect(pFunction, iMinLen, PAGE_EXECUTE_READWRITE, OldProtect)) then begin //CopyMemory(@Trampoline64_Jump, @Trampoline64_DefaultValues, SizeOf(TTrampoline64)); Trampoline64_Jump := Trampoline64_DefaultValues; Trampoline64_Jump.asmAddress := UInt64(pHookFunction); CopyMemory(pFunction, @Trampoline64_Jump, SizeOf(TTrampoline64)); VirtualProtect(pFunction, iMinLen, OldProtect, OldProtect); end; end; end; end. unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, hde64, uBytesToPascal2, uHook64; type TForm1 = class(TForm) Button1: TButton; Memo1: TMemo; Button2: TButton; Button3: TButton; Button4: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button4Click(Sender: TObject); procedure Button3Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} function Hook_MessageBoxW(p1: Int64; lpText, lpCaption: PWideChar; p4: Cardinal): Integer; stdcall; begin Result := 0; MessageBoxA(0, 'Intercepted Message!', 'Hook', MB_OK); end; procedure Test; begin MessageBoxW(0, 'Test', 'Program', MB_OK); end; procedure TForm1.Button1Click(Sender: TObject); var hs: TDisasm; i, c, len, offset: Integer; opcodes: String; begin offset := 0; for i := 0 to 10 - 1 do begin len := hde64_disasm(Pointer(UInt64(GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')) + offset), hs); opcodes := ''; for c := 0 to len - 1 do begin opcodes := opcodes + IntToHex(PByte(UInt64(GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')) + offset + c)^, 2) + ' '; end; Memo1.Lines.Add(opcodes); offset := offset + len; end; //Memo1.Lines.Add(IntToStr( )); end; procedure TForm1.Button2Click(Sender: TObject); begin Memo1.Lines.Add(IntToStr(GetMinHookLength(16, @Test))); end; procedure TForm1.Button3Click(Sender: TObject); begin Test; end; procedure TForm1.Button4Click(Sender: TObject); begin InstallHook64(@Hook_MessageBoxW, GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW')); end; end.
  11. Today just the funciton to get the length necessary for the trampoline: function GetMinLength(iLen: Cardinal; p: Pointer): Integer; var hs: TDisasm; begin Result := 0; repeat try Result := Cardinal(Result) + hde64_disasm(Pointer(UInt64(p) + Result), hs); except Result := -1; Break; end; until (Cardinal(Result) >= iLen); end;
  12. What worries me is that if we are going to hook a really short function, we might end up corrupting code that comes after the function...
  13. .text:00000000005A0300 sub_5A0300 proc near ; DATA XREF: sub_5A0340:loc_5A036Eo .text:00000000005A0300 ; sub_5A0340+69o ... .text:00000000005A0300 sub rsp, 28h .text:00000000005A0304 xor rcx, rcx ; hWnd .text:00000000005A0307 lea rdx, aTeste ; "Teste" .text:00000000005A030E lea r8, aProgram ; "Program" .text:00000000005A0315 xor r9, r9 ; uType .text:00000000005A0318 call MessageBoxW .text:00000000005A031D add rsp, 28h .text:00000000005A0321 retn .text:00000000005A0321 sub_5A0300 endp that would be the code in ASM, according to IDA-64 I like ollydbg so much, it is a shame it cant work on 64bit files When running the sample project for testing it returns this: Just forget the last two lines, the function is until C3.... ret So yes, it works...
  14. ok, coded a little.. I am lazy so I work slow, as Tesla would say: (* * Hacker Disassembler Engine 64 * Copyright (c) 2006-2009, Veacheslav Patkov * aLL rights reserved. * * hde64.pas : pascal header file (Free pascal, Delphi) * *) unit hde64; interface uses windows; type TDisasm = packed record len : byte; { length of command } p_rep : byte; { rep/repz (0xf3) & repnz (0xf2) prefix } p_lock : byte; { lock prefix: 0xf0 } p_seg : byte; { segment prefix: 0x2e,0x36,0x3e,0x26,0x64,0x65 } p_66 : byte; { operand-size override prefix: 0x66 } p_67 : byte; { address-size override prefix: 0x67 } rex : byte; rex_w : byte; rex_r : byte; rex_x : byte; rex_b : byte; opcode : byte; { opcode } opcode2 : byte; { second opcode (if first opcode is 0x0f) } modrm : byte; { ModR/M byte } modrm_mod : byte; { mod field of ModR/M } modrm_reg : byte; { reg field of ModR/M } modrm_rm : byte; { r/m field of ModR/M } sib : byte; { SIB byte } sib_scale : byte; { scale field of SIB } sib_index : byte; { index field of SIB } sib_base : byte; { base field of SIB } imm8 : byte; { immediate value imm8 } imm16 : word; { immediate value imm16 } imm32 : dword; { immediate value imm32 } imm64 : dword64; { immediate value imm32 } disp8 : byte; { displacement disp8 } disp16 : word; { displacement disp16 } disp32 : dword; { displacement disp32 } flags : dword; { displacement disp32 } end; function hde64_disasm(code: pointer; var hs: TDisasm): dword; cdecl; implementation {$LINK 'hde64.obj'} function hde64_disasm(code: pointer; var hs: TDisasm): dword; cdecl; external; end. /* * Hacker Disassembler Engine 64 C * Copyright (c) 2008-2009, Vyacheslav Patkov. * All rights reserved. * */ #include <stdint.h> #include <string.h> #include "../include/hde64.h" #include "table64.h" unsigned int hde64_disasm(const void *code, hde64s *hs) { uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0; uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0; uint8_t op64 = 0; memset(hs,0,sizeof(hde64s)); for (x = 16; x; x--) switch (c = *p++) { case 0xf3: hs->p_rep = c; pref |= PRE_F3; break; case 0xf2: hs->p_rep = c; pref |= PRE_F2; break; case 0xf0: hs->p_lock = c; pref |= PRE_LOCK; break; case 0x26: case 0x2e: case 0x36: case 0x3e: case 0x64: case 0x65: hs->p_seg = c; pref |= PRE_SEG; break; case 0x66: hs->p_66 = c; pref |= PRE_66; break; case 0x67: hs->p_67 = c; pref |= PRE_67; break; default: goto pref_done; } pref_done: hs->flags = (uint32_t)pref << 23; if (!pref) pref |= PRE_NONE; if ((c & 0xf0) == 0x40) { hs->flags |= F_PREFIX_REX; if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8) op64++; hs->rex_r = (c & 7) >> 2; hs->rex_x = (c & 3) >> 1; hs->rex_b = c & 1; if (((c = *p++) & 0xf0) == 0x40) { opcode = c; goto error_opcode; } } if ((hs->opcode = c) == 0x0f) { hs->opcode2 = c = *p++; ht += DELTA_OPCODES; } else if (c >= 0xa0 && c <= 0xa3) { op64++; if (pref & PRE_67) pref |= PRE_66; else pref &= ~PRE_66; } opcode = c; cflags = ht[ht[opcode / 4] + (opcode % 4)]; if (cflags == C_ERROR) { error_opcode: hs->flags |= F_ERROR | F_ERROR_OPCODE; cflags = 0; if ((opcode & -3) == 0x24) cflags++; } x = 0; if (cflags & C_GROUP) { uint16_t t; t = *(uint16_t *)(ht + (cflags & 0x7f)); cflags = (uint8_t)t; x = (uint8_t)(t >> 8); } if (hs->opcode2) { ht = hde64_table + DELTA_PREFIXES; if (ht[ht[opcode / 4] + (opcode % 4)] & pref) hs->flags |= F_ERROR | F_ERROR_OPCODE; } if (cflags & C_MODRM) { hs->flags |= F_MODRM; hs->modrm = c = *p++; hs->modrm_mod = m_mod = c >> 6; hs->modrm_rm = m_rm = c & 7; hs->modrm_reg = m_reg = (c & 0x3f) >> 3; if (x && ((x << m_reg) & 0x80)) hs->flags |= F_ERROR | F_ERROR_OPCODE; if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { uint8_t t = opcode - 0xd9; if (m_mod == 3) { ht = hde64_table + DELTA_FPU_MODRM + t*8; t = ht[m_reg] << m_rm; } else { ht = hde64_table + DELTA_FPU_REG; t = ht[t] << m_reg; } if (t & 0x80) hs->flags |= F_ERROR | F_ERROR_OPCODE; } if (pref & PRE_LOCK) { if (m_mod == 3) { hs->flags |= F_ERROR | F_ERROR_LOCK; } else { uint8_t *table_end, op = opcode; if (hs->opcode2) { ht = hde64_table + DELTA_OP2_LOCK_OK; table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; } else { ht = hde64_table + DELTA_OP_LOCK_OK; table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; op &= -2; } for (; ht != table_end; ht++) if (*ht++ == op) { if (!((*ht << m_reg) & 0x80)) goto no_lock_error; else break; } hs->flags |= F_ERROR | F_ERROR_LOCK; no_lock_error: ; } } if (hs->opcode2) { switch (opcode) { case 0x20: case 0x22: m_mod = 3; if (m_reg > 4 || m_reg == 1) goto error_operand; else goto no_error_operand; case 0x21: case 0x23: m_mod = 3; if (m_reg == 4 || m_reg == 5) goto error_operand; else goto no_error_operand; } } else { switch (opcode) { case 0x8c: if (m_reg > 5) goto error_operand; else goto no_error_operand; case 0x8e: if (m_reg == 1 || m_reg > 5) goto error_operand; else goto no_error_operand; } } if (m_mod == 3) { uint8_t *table_end; if (hs->opcode2) { ht = hde64_table + DELTA_OP2_ONLY_MEM; table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM; } else { ht = hde64_table + DELTA_OP_ONLY_MEM; table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; } for (; ht != table_end; ht += 2) if (*ht++ == opcode) { if (*ht++ & pref && !((*ht << m_reg) & 0x80)) goto error_operand; else break; } goto no_error_operand; } else if (hs->opcode2) { switch (opcode) { case 0x50: case 0xd7: case 0xf7: if (pref & (PRE_NONE | PRE_66)) goto error_operand; break; case 0xd6: if (pref & (PRE_F2 | PRE_F3)) goto error_operand; break; case 0xc5: goto error_operand; } goto no_error_operand; } else goto no_error_operand; error_operand: hs->flags |= F_ERROR | F_ERROR_OPERAND; no_error_operand: c = *p++; if (m_reg <= 1) { if (opcode == 0xf6) cflags |= C_IMM8; else if (opcode == 0xf7) cflags |= C_IMM_P66; } switch (m_mod) { case 0: if (pref & PRE_67) { if (m_rm == 6) disp_size = 2; } else if (m_rm == 5) disp_size = 4; break; case 1: disp_size = 1; break; case 2: disp_size = 2; if (!(pref & PRE_67)) disp_size <<= 1; } if (m_mod != 3 && m_rm == 4) { hs->flags |= F_SIB; p++; hs->sib = c; hs->sib_scale = c >> 6; hs->sib_index = (c & 0x3f) >> 3; if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) disp_size = 4; } p--; switch (disp_size) { case 1: hs->flags |= F_DISP8; hs->disp.disp8 = *p; break; case 2: hs->flags |= F_DISP16; hs->disp.disp16 = *(uint16_t *)p; break; case 4: hs->flags |= F_DISP32; hs->disp.disp32 = *(uint32_t *)p; } p += disp_size; } else if (pref & PRE_LOCK) hs->flags |= F_ERROR | F_ERROR_LOCK; if (cflags & C_IMM_P66) { if (cflags & C_REL32) { if (pref & PRE_66) { hs->flags |= F_IMM16 | F_RELATIVE; hs->imm.imm16 = *(uint16_t *)p; p += 2; goto disasm_done; } goto rel32_ok; } if (op64) { hs->flags |= F_IMM64; hs->imm.imm64 = *(uint64_t *)p; p += 8; } else if (!(pref & PRE_66)) { hs->flags |= F_IMM32; hs->imm.imm32 = *(uint32_t *)p; p += 4; } else goto imm16_ok; } if (cflags & C_IMM16) { imm16_ok: hs->flags |= F_IMM16; hs->imm.imm16 = *(uint16_t *)p; p += 2; } if (cflags & C_IMM8) { hs->flags |= F_IMM8; hs->imm.imm8 = *p++; } if (cflags & C_REL32) { rel32_ok: hs->flags |= F_IMM32 | F_RELATIVE; hs->imm.imm32 = *(uint32_t *)p; p += 4; } else if (cflags & C_REL8) { hs->flags |= F_IMM8 | F_RELATIVE; hs->imm.imm8 = *p++; } disasm_done: if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) { hs->flags |= F_ERROR | F_ERROR_LENGTH; hs->len = 15; } return (unsigned int)hs->len; } I used Visual Studio 2015 to compile the .obj file and then used it on RAD Studio XE2. Compiled for 64 bit... unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, hde64, uBytesToPascal2; type TForm1 = class(TForm) Button1: TButton; Memo1: TMemo; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure Test; begin MessageBox(0, 'Teste', 'Program', MB_OK); end; procedure TForm1.Button1Click(Sender: TObject); var hs: TDisasm; i, c, len, offset: Integer; opcodes: String; begin offset := 0; for i := 0 to 10 - 1 do begin len := hde64_disasm(Pointer(UInt64(@Test) + offset), hs); opcodes := ''; for c := 0 to len - 1 do begin opcodes := opcodes + IntToHex(PByte(UInt64(@Test) + offset + c)^, 2) + ' '; end; Memo1.Lines.Add(opcodes); offset := offset + len; end; //Memo1.Lines.Add(IntToStr( )); end; end. Then this is just a sample to get the 10 instructions from a certain address. Just for testing purposes. That will be enough to create our function to capture the necessary instructions out of the original function and copy elsewhere, so we can insert the trampoline and hook the function. after executed the trampoline and our own interception function, we execute the copied instructions and at the end do another trampoline to the original code plus the offset of the overwritten instructions.
  15. Ok, already found an improvement... I downloaded the EasyHook as it is an active project so it will be good to steal the idea and rip the code: Because yes, I am just a script kiddie, I like when there is code already done and I just have to copy and paste. In this case, copy, paste and translate. // 50 push rax // 48 b8 00 00 00 00 00 00 00 00 mov rax, 0x0 // 48 87 04 24 xchg QWORD PTR[rsp], rax // c3 ret This way we save the old value in RAX. It is a smart idea, uses a lot of bytes though... who cares... I hope hde is still around some where I guess there was a hde64
  • Who's Online   0 Members, 0 Anonymous, 6 Guests (See full list)

    There are no registered users currently online