📄 disasm.pas
字号:
unit DisAsm;
interface
uses
SysUtils, Classes;
type
EDisAsmError = class(Exception);
TRegister = (rEax, rEcx, rEdx, rEbx, rEsp, rEbp, rEsi, rEdi);
TdaRef = record
MultiplyReg1: Integer;
ARegister1: TRegister;
MultiplyReg2: Integer;
ARegister2: TRegister;
Immidiate: PChar;
end;
TJumpInstrProc = procedure (Param: Pointer; ValueAddress, JumpAddress: PChar; var Result: string);
TCallInstrProc = procedure (Param: Pointer; ValueAddress, CallAddress: PChar; var Result: string);
TAddressRefProc = procedure (Param: Pointer; ValueAddress, RefAddress: PChar; var Result: string);
TRefProc = procedure (Param: Pointer; Ref: TdaRef; RefSize: Integer; var Result: string);
TImmidiateDataProc = procedure (Param: Pointer; ValueAddress: PChar; OperandSize: Integer; Sigend: Boolean; var Result: string);
TDisAsm = class(TObject)
public
OnJumpInstr: TJumpInstrProc;
OnCallInstr: TCallInstrProc;
OnAddressRef: TAddressRefProc;
OnRef: TRefProc;
OnImmidiateData: TImmidiateDataProc;
Param: Pointer;
function GetInstruction(Address: PChar; var Size: Integer): string;
end;
const
modrmReg = $38; // Reg part of the ModRM byte, ??XXX???
modrmMod = $C0; // Mod part of the ModRM byte, XX??????
modrmRM = $07; // RM part of the ModRM byte, ?????XXX
function SignedIntToHex(Value: Integer; Digits: Integer): string;
function FindFirstSimpleCallTo(CallAddress, SearchAddress: PChar; SearchSize: Integer): PChar;
function FindLastSimpleCallTo(CallAddress, SearchAddress: PChar; SearchSize: Integer): PChar;
implementation
uses
Windows, DisAsmTables, DeDeRES;
// Convert an Integer to a string including a + or - and $ character.
function SignedIntToHex(Value: Integer; Digits: Integer): string;
begin
if Value < 0 then
Result := '-$' + IntToHex(-Integer(Value), Digits)
else
Result := '+$' + IntToHex(Integer(Value), Digits);
end;
// Reads the instruction at Address and return the Size and the assembler string
// representing the instruction.
function TDisAsm.GetInstruction(Address: PChar; var Size: Integer): string;
var
Ref: TdaRef;
{ Reading is getting the value at Address + Size and then increment Size
with the size of the read value }
function ReadDWord: DWord;
begin
if IsBadReadPtr(Address, 4) then
raise EDisAsmError.Create(err_not_enuff_code);
Result := PDWord(Address + Size)^;
Inc(Size, 4);
end;
function ReadWord: Word;
begin
if IsBadReadPtr(Address, 2) then
raise EDisAsmError.Create(err_not_enuff_code);
Result := PWord(Address + Size)^;
Inc(Size, 2);
end;
function ReadByte: Byte;
begin
if IsBadReadPtr(Address, 1) then
raise EDisAsmError.Create(err_not_enuff_code);
Result := PByte(Address + Size)^;
Inc(Size, 1);
end;
function GetRefAddress: string;
var
RefAddress: PChar;
begin
RefAddress := PChar(ReadDWord);
Ref.Immidiate := Ref.Immidiate + Integer(RefAddress);
Result := '$' + IntToHex(DWord(RefAddress), 4);
if Assigned(OnAddressRef) then
OnAddressRef(Param, Address + Size - 4, RefAddress, Result);
Result := '^' + Chr(Length(Result)) + Result;
end;
// Only read the ModRM byte the first time it is asked.
// After that return the previous read ModRM byte
var
XHasModRM: Boolean;
XModRM: Byte;
function ModRM: Byte;
begin
if not XHasModRM then
begin
XModRM := ReadByte;
XHasModRM := True;
end;
Result := XModRM;
end;
// Only read the Sib byte the first time it is asked.
// After that return the previous read Sib byte
var
XHasSib: Boolean;
XSib: Byte;
function Sib: Byte;
begin
if not XHasSib then
begin
XSib := ReadByte;
XHasSib := True;
end;
Result := XSib;
end;
var
DeffOperandSize: Integer;// Default = 4, but may be changed by operand prefix.
AddressSize: Integer; // Default = 4, but may be changed by operand prefix.
OperandSize: Integer;
SegOverride: Boolean;
SegName: string;
MustHaveSize: Boolean;
// Operand anlayser.
function Operand(AddrMethod, OperandType, EnhOperandType: char): string;
// Returns the name of the register specified by Reg using OperandType
// to determen the size.
function GetRegName(Reg: Byte): string;
const
ByteRegs1: array[0..3] of char = 'acdb';
ByteRegs2: array[0..1] of char = 'lh';
WordRegs1: array[0..7] of char = 'acdbsbsd';
WordRegs2: array[0..4] of char = 'xxpi';
begin
if OperandSize = 1 then
Result := ByteRegs1[Reg mod 4] + ByteRegs2[Reg div 4]
else
begin
if OperandSize = 4 then
Result := 'e'
else
Result := '';
Result := Result + WordRegs1[Reg] + WordRegs2[Reg div 2];
end;
end;
// Returns the description of the effective address in the ModRM byte.
function GetEffectiveAddress(EAMustHaveSize: Boolean): string;
var
RM: Byte;
AMod: Byte;
function ReadSib: string;
var
SI: Byte;
SS: Byte;
Base: Byte;
begin
Base := Sib and $07; {?????XXX}
SI := (Sib shr 3) and $07; {??XXX???}
SS := (Sib shr 6) and $03; {XX??????}
// Save register used by Base
case Base of
0: Result := '[eax';
1: Result := '[ecx';
2: Result := '[edx';
3: Result := '[ebx';
4: Result := '[esp';
5: if AMod <> 0 then
Result := '[ebp'
else
Result := '[' + GetRefAddress;
6: Result := '[esi';
7: Result := '[edi';
end;
if (Base <> 5) or (AMod = 0) then
begin
Ref.ARegister2 := TRegister(Base);
Ref.MultiplyReg2 := 1;
end;
// result register Scaled Index
case SI of
0: Result := Result + '+eax';
1: Result := Result + '+ecx';
2: Result := Result + '+edx';
3: Result := Result + '+ebx';
5: Result := Result + '+ebp';
6: Result := Result + '+esi';
7: Result := Result + '+edi';
end;
if SI <> 4 then
Ref.ARegister1 := TRegister(SI);
// No SS when SI = 4
if SI <> 4 then
// Save modification made by SS
case SS of
0: begin Result := Result + ''; Ref.MultiplyReg1 := 1; end;
1: begin Result := Result + '*2'; Ref.MultiplyReg1 := 2; end;
2: begin Result := Result + '*4'; Ref.MultiplyReg1 := 4; end;
3: begin Result := Result + '*8'; Ref.MultiplyReg1 := 8; end;
end;
end;
var
I: Integer;
begin
RM := ModRM and modrmRM;
AMod := ModRm and modrmMod shr 6;
// Effective address is a register;
if AMod = 3 then
begin
Result := GetRegName(RM);
Exit;
end;
Result := '%s' + Chr(OperandSize);
// override seg name
if SegOverride then
Result := Result + SegName + ':';
// Include the Size if it is other than 4
if OperandSize <> 4 then
MustHaveSize := True;
if AddressSize = 4 then
begin
// disp32.
if (AMod = 0) and (RM = 5) then
begin
Result := Result + '[' + GetRefAddress + ']';
if Assigned(OnRef) then
OnRef(Param, Ref, OperandSize, Result);
Exit;
end;
end
else
begin
// disp16
if (AMod = 0) and (RM = 6) then
begin
Result := Result + '[' + GetRefAddress + ']';
if Assigned(OnRef) then
OnRef(Param, Ref, OperandSize, Result);
Exit;
end;
end;
// Analyse RM Value.
if AddressSize = 2 then
case RM of
0: Result := Result + '[bx+si';
1: Result := Result + '[bx+di';
2: Result := Result + '[bp+si';
3: Result := Result + '[bp+di';
4: Result := Result + '[si';
5: Result := Result + '[di';
6: Result := Result + '[bp';
7: Result := Result + '[bx';
end
else
begin
case RM of
0: Result := Result + '[eax';
1: Result := Result + '[ecx';
2: Result := Result + '[edx';
3: Result := Result + '[ebx';
4: Result := Result + ReadSIB;
5: Result := Result + '[ebp';
6: Result := Result + '[esi';
7: Result := Result + '[edi';
end;
if RM <> 4 then
begin
Ref.ARegister1 := TRegister(RM);
Ref.MultiplyReg1 := 1;
end;
end;
// possible disp value dependent of Mod.
case AMod of
// no disp
0: Result := Result + ']';
// disp8
1: begin
I := ShortInt(ReadByte);
Result := Result + SignedIntToHex(I, 2) + ']';
Inc(Ref.Immidiate, I);
end;
// disp32 or disp16
2: Result := Result + '+' + GetRefAddress + ']';
end;
// Call the OnRef proc.
if Assigned(OnRef) then
OnRef(Param, Ref, OperandSize, Result);
end;
var
I: Integer;
begin
Result := '';
// Save the operand size using the DeffOperandSize and SubType
case OperandType of
// two Word or two DWord, only used by BOUND
'a': if DeffOperandSize = 2 then
OperandSize := 4
else
OperandSize := 8;
// Byte.
'b': OperandSize := 1;
// Byte or word
'c': if DeffOperandSize = 2 then
OperandSize := 1
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -