{ YAD 0.13 (Yet Another Disassembler) (x) herm1t@vx.netlux.org, 2008 Pascal Coded By Anskya[2009] } unit VxYAD32; interface {$define YAD_DATA_H} {$define YAD_PACK6} {.$define CHECK_LOCK} {.$define CHECK_ARGS} const C_DATA1 = $0001; C_DATA2 = $0002; C_DATA66 = $0004; C_ADDR1 = $0008; C_ADDR67 = $0010; C_MODRM = $0020; C_SIB = $0040; C_BAD = $0080; C_REL = $0100; C_STOP = $0200; C_PREGRP = $4000; C_GROUP = $8000; C_ERROR = $ffff; YAD_GROUP_MASK = $3fff; type uint8_t = BYTE; puint8_t = ^uint8_t; uint16_t = WORD; puint16_t = ^uint16_t; uint32_t = Longword; puint32_t = ^uint32_t; TArray_uint16_t = Array[WORD] Of uint16_t; PArray_uint16_t = ^TArray_uint16_t; yad_p = ^yad_t; yad_t = packed record flags: uint32_t; len: uint8_t; p_seg: uint8_t; p_lock: uint8_t; p_rep: uint8_t; p_67: uint8_t; p_66: uint8_t; opcode: uint8_t; opcode2: uint8_t; modrm: uint8_t; sib: uint8_t; addrsize: uint8_t; datasize: uint8_t; data: packed record case uint8_t of 0: (data1: uint8_t); 1: (data2: uint16_t); 2: (data4: uint32_t); end; addr: packed record case uint8_t of 0: (addr1: uint8_t); 1: (addr2: uint16_t); 2: (addr4: uint32_t); end; end; function yad_asm(opcode: puint8_t; var diza: yad_t): Integer; stdcall; function yad_disasm(opcode: puint8_t; var diza: yad_t): Integer; stdcall; implementation const YAD_VALUES_OFFSET = 444; YAD_FLOAT_OFFSET = 528; YAD_3DNOW_OFFSET = 584; const yad_data: Array[0..615] Of uint8_t = ( $00, $00, $00, $04, $20, $c3, $00, $00, $00, $04, $20, $c4, $00, $00, $00, $04, $20, $c3, $00, $00, $00, $04, $20, $c3, $00, $00, $00, $04, $21, $03, $00, $00, $00, $04, $21, $03, $00, $00, $00, $04, $21, $03, $00, $00, $00, $04, $21, $03, $0c, $30, $c3, $0c, $30, $c3, $0c, $30, $c3, $0c, $30, $c3, $0c, $30, $c3, $0c, $30, $c3, $0c, $30, $c3, $0c, $30, $c3, $0c, $30, $00, $10, $41, $04, $08, $50, $46, $0c, $30, $c3, $1c, $71, $c7, $1c, $71, $c7, $1c, $71, $c7, $1c, $71, $c7, $18, $51, $86, $00, $00, $00, $00, $00, $00, $00, $00, $08, $0c, $30, $c3, $0c, $30, $c3, $0c, $32, $43, $0c, $30, $c3, $28, $a2, $8a, $0c, $30, $c3, $04, $20, $c3, $0c, $30, $c3, $04, $10, $41, $04, $10, $41, $08, $20, $82, $08, $20, $82, $18, $62, $cc, $00, $03, $4e, $3c, $32, $cc, $0c, $10, $cc, $00, $00, $00, $04, $10, $c3, $00, $00, $00, $00, $00, $00, $1c, $71, $c7, $04, $10, $41, $41, $14, $93, $0c, $30, $c3, $10, $31, $04, $0c, $35, $15, $0c, $30, $c3, $0c, $35, $97, $61, $90, $00, $10, $30, $c3, $0c, $31, $04, $10, $00, $c6, $69, $a6, $9b, $6d, $b7, $1b, $00, $00, $00, $00, $00, $00, $00, $00, $00, $10, $41, $04, $6d, $b6, $9b, $69, $a6, $db, $0c, $30, $c3, $0c, $31, $03, $10, $41, $04, $10, $41, $04, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $6d, $a7, $5d, $6d, $b6, $db, $69, $a6, $9c, $69, $a6, $9a, $6d, $b6, $db, $6d, $b6, $db, $6d, $b6, $db, $79, $e6, $dc, $7e, $08, $21, $6d, $b6, $c3, $10, $41, $04, $8a, $27, $1c, $41, $04, $10, $41, $04, $10, $41, $04, $10, $41, $04, $10, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $0c, $30, $c0, $18, $01, $04, $0c, $30, $c0, $18, $08, $c0, $00, $00, $00, $00, $00, $00, $10, $49, $00, $00, $00, $00, $00, $07, $e5, $9a, $69, $a7, $0c, $30, $c3, $0c, $30, $c3, $89, $b6, $db, $6d, $ba, $1b, $6d, $b6, $db, $6d, $b6, $db, $6d, $b6, $db, $6d, $ba, $1b, $6d, $b6, $db, $6d, $b6, $db, $a5, $b6, $db, $6d, $b6, $db, $6d, $b6, $db, $6d, $b6, $c4, $04, $41, $04, $10, $41, $04, $08, $41, $04, $10, $41, $04, $04, $10, $c3, $0c, $30, $c3, $08, $20, $c3, $0c, $30, $c3, $10, $41, $04, $10, $40, $c3, $0c, $33, $0c, $0c, $40, $c3, $0c, $30, $c4, $0c, $31, $04, $04, $40, $44, $04, $41, $01, $10, $41, $01, $10, $41, $04, $04, $10, $41, $10, $40, $c4, $20, $00, $01, $00, $04, $00, $00, $00, $ff, $ff, $24, $00, $21, $00, $01, $01, $37, $81, $06, $00, $10, $00, $02, $02, $00, $02, $00, $82, $08, $82, $03, $00, $04, $01, $04, $03, $06, $02, $01, $03, $10, $82, $18, $82, $1e, $82, $26, $82, $1a, $82, $2e, $82, $3f, $40, $ef, $40, $ed, $40, $08, $41, $4c, $42, $b0, $40, $36, $82, $3d, $82, $f2, $40, $3f, $80, $44, $82, $09, $41, $38, $42, $36, $81, $3e, $40, $23, $42, $00, $00, $fe, $00, $cc, $80, $00, $00, $00, $00, $00, $00, $ff, $fd, $ff, $ff, $00, $00, $00, $00, $e0, $00, $00, $ff, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $ff, $ff, $00, $00, $00, $fd, $00, $00, $00, $00, $00, $00, $00, $00, $fe, $00, $00, $ff, $ff, $cf, $ff, $cf, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $bb, $2e, $bb, $2e, $bb, $2e, $77, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff ); function fetch(i: uint32_t): uint16_t; var bResult: Boolean; t: uint32_t; {$ifndef YAD_PACK6} yad_table: puint16_t; {$endif} begin {$ifdef YAD_PACK6} t := puint32_t(Longword(@yad_data) + (((i shl 1) + i) shr 2))^; i := (i and 3); if (i = 0) then t := t shr 2 else begin Dec(i); bResult := (i = 0); if (bResult) then t := ((t and 3) shl 4) or ((t shr 12) and 15) else begin Dec(i); bResult := (i = 0); if (bResult) then t := ((t and 15) shl 2) or ((t shr 14) and 3); end; end; t := (t and 63) shl 1; Result := puint16_t(LongWord(@yad_data) + YAD_VALUES_OFFSET + t)^; {$else} yad_table := puint16_t(LongWord(@yad_data) + YAD_VALUES_OFFSET); Result := PArray_uint16_t(yad_table)[yad_data[i]]; {$endif} end; function yad_disasm(opcode: puint8_t; var diza: yad_t): Integer; stdcall; label bad, lock_ok, sf; var p: puint8_t; c, a, datasize, addrsize: uint8_t; flags: uint16_t; j, i, imod, rm, reg: uint32_t; begin Result := 0; //ZeroMemory(diza, SizeOf(TYad_Struct)); for i := 0 to (SizeOf(yad_t) - 1) do begin PBYTE(LongWord(@diza) + i)^ := 0; end; datasize := 4; addrsize := 4; p := opcode; //flags := 0; c := 0; if ((PWORD(p)^ = $0000) or (PWORD(p)^ = $FFFF)) then diza.flags := diza.flags or C_BAD; {* prefixes *} while (True) do begin c := p^; Inc(p); if (c = $66) then begin if (diza.p_66 > 0) then goto bad; diza.p_66 := c; datasize := 2; Continue; end; if (c = $67) then begin if (diza.p_67 > 0) then goto bad; diza.p_67 := c; addrsize := 2; Continue; end; if (((c and $FE) = $64) or ((c and $E7) = $26)) then begin if (diza.p_seg > 0) then goto bad; diza.p_seg := c; Continue; end; if ((c and $FE) = $F2) then begin if (diza.p_rep > 0) then goto bad; diza.p_rep := c; Continue; end; if (c = $F0) then begin if (diza.p_lock > 0) then goto bad; diza.p_lock := c; Continue; end; Break; bad: // MAX Loop---or Exit diza.flags := diza.flags or C_BAD; end; {* opcode *} diza.opcode := c; if (diza.opcode = $0F) then begin diza.opcode2 := p^; Inc(p); j := 256 + diza.opcode2; end else j := c; {* instruction flags by opcode *} flags := fetch(j); if (flags = C_ERROR) then Exit; {* parse ModRM and SIB, (prefix) groups, FPU *} if ((flags and (C_MODRM or C_GROUP or C_PREGRP)) > 0) then begin c := p^; Inc(p); diza.modrm := c; imod := c shr 6; reg := (c shr 3) and 7; rm := c and 7; {$ifdef CHECK_LOCK} {* check lock prefix *} if (diza.p_lock > 0) then begin if (imod = 3) then Exit; {* two byte opcodes *} if (diza.opcode2 > 0) then begin Result := 0; c := diza.opcode2; {* BT BTS BTR BTC *} if ((c <> $BA) or (reg <> 4)) then goto lock_ok; {* CMPXCHG *} if ((c = $C7) and (reg = 1)) then goto lock_ok; {* BTS XADD XADD CMPXCHG CMPXCHG BTR BTC *} {* ab c0 c1 b0 b1 b3 bb *} if ((c = $AB) or (((c and $FC) = $B0) and (c <> $B2)) or ((c and $FE) = $C0) or (c = $BB)) then goto lock_ok; {* f0 0f 20/22 MOV Rd,CR8D / MOV CR8D,Rd *} if ((c = $20) or (c = $22)) then goto lock_ok; end else begin c := diza.opcode and $FE; {* 00 01 08 09 10 11 18 19 20 21 28 29 30 31 *} if (((c and 7) = 0) or ((c shr 3) < 7)) then goto lock_ok; {* 86 87 *} if (c = $86) then goto lock_ok; if ((c = $F6) and ((reg and $FE) = 2)) then goto lock_ok; if ((c = $FE) and ((reg and $FE) = 0)) then goto lock_ok; {* group1 *} if (((diza.opcode and $FC) = $80) and (reg <> 7)) then goto lock_ok; end; Exit; end; lock_ok: {$endif} // CHECK_LOCK: after lock, f0 0f 20 ... // https://forums.symantec.com/syment/blog/article?message.uid=305479 if ((j and $FFFC) = $120) then imod := 3; if ((flags and (C_GROUP or C_PREGRP)) > 0) then begin if ((flags and C_GROUP) > 0) then begin i := reg; end else if (diza.p_rep = $F3) then begin i := 1; end else if (diza.p_66 > 0) then begin i := 2; end else if (diza.p_rep = $F2) then begin i := 3; end else i := 0; flags := C_MODRM or fetch((flags and YAD_GROUP_MASK) + i); {* fixes for groups 13-15 *} c := diza.opcode2; if (((c and $FC) = $70) and (c <> $70)) then begin if (diza.p_rep > 0) then Exit; {* PSRLDQ / PSLLDQ VRo, Ib *} if ((c = $73) and (diza.p_66 > 0) and ((reg = 3) or (reg = 7))) then flags := C_DATA1; {$ifdef CHECK_ARGS} if (imod <> 3) then Exit; {$endif} end; if (flags = C_ERROR) then Exit; end else begin {* check FPU instructions *} c := diza.opcode; if ((c >= $D9) and (c <= $DF)) then begin {* d8 is fully allocated *} c := ((c - $D9) shl 3) + uint8_t(reg); if (imod = 3) then begin if ((yad_data[YAD_FLOAT_OFFSET + c] and (1 shl rm)) > 0) then Exit; end else begin // *d9 /1* or *db /4* or *db /6* or *dd /5* if ((c = $01) or (c = $14) or (c = $16) or (c = $25)) then Exit; end; end; end; { * ModRM and SIB * } if (imod <> 3) then begin if (diza.p_67 > 0) then begin if ((imod = 0) and (rm = 6)) then goto sf; end else begin if (rm = 4) then begin c := p^; Inc(p); flags := flags or C_SIB; diza.sib := c; end; if ((imod = 0) and ((rm = 5) or ((diza.sib and 7) = 5))) then goto sf; end; if (imod = 1) then flags := flags or C_ADDR1; if (imod = 2) then begin sf: flags := flags or C_ADDR67; end; {$ifdef CHECK_ARGS} c := diza.opcode2; if (c <> 0) then begin if ( ((diza.p_rep = 0) and ( {* MOVMSKPS / MOVMSKPD *} (c = $50) or {* PEXTRW *} (c = $C5) or {* PMOVMSKB *} (c = $D7) or {* MASKMOVQ / MASKMOVDQU *} (c = $F7) )) {* MOVQ2DQ / MOVDQ2Q *} or ((diza.p_rep <> 0 ) and (c = $D6)) ) then Exit; end; {$endif} {* CHECK ARGS *} end else begin {$ifdef CHECK_ARGS} {* mod == 11, check operands,the code was taken from HDE32 *} if (diza.opcode2 > 0) then begin c := diza.opcode2; if ( {* group#7 0f 01 SGDT/SIDT/LGDT/LIDT Ms/../../../INVLPG M *} ( (c = $01) and ((reg < 4) or (reg = 7)) ) or {* group#9 0f c7 CMPXCHG Mq *} ( (c = $C7) and (reg = 1) ) or {* 0f b2 LSS Gz,Mp *} {* 0f b4 LFS Gz,Mp *} {* 0f b5 LGS Gz,Mp *} ( (c = $B2) or (c = $B4) or (c = $B5) ) or {* group#16 0f ae FXSAVE M512 / FXRSTOR M512 / LDMXCSR Md / STMXCSR Md / XSAVE M *} ( (c = $AE) and (reg < 5) ) or {* FIXME: more checks here, SSE... *} {* MOVLPD / MOVHPD / CVTPI2PD / MOVQ / MOVNTDQ *} ( (diza.p_66 > 0) and ((c = $12) or (c = $16) or (c = $E7)) ) or {* MOVLPS,MOVLPD / MOVHPS, MOVHPD / MOVNTPS, MOVNTPD *} ( (diza.p_rep = 0) and ((c = $13) or (c = $17) or (c = $2B)) ) or {* LDDQU *} ( (diza.p_rep = $F2) and (c = $F0) ) or {* MOVNTI *} (c = $C3) ) then Exit; end else begin c := diza.opcode; if ( {* 62 BOUND Gv,Ma *} {* 8d LEA Gv,M *} {* c4 LES Gz,Mp *} {* c5 LDS Gz,Mp *} ((c = $62) or (c = $8D) or ((c and $FE) = $C4)) or {* group#5 CALL Mp, JMP Mp *} ((c = $FF) and ((reg = 3) or (reg = 5))) ) then Exit; end; {$endif} {* CHECK_ARGS *} end; {* mod == 3 *} {$ifdef CHECK_ARGS} c := diza.opcode; if ( ((c = $8E) and ((reg = 1) or (reg > 5))) or {* MOV Sw, Mw/Rv *} ((c = $8C) and (reg >= 6)) {* MOV Mw/Rv, Sw *} ) then Exit; c := diza.opcode2; if ( (((c and $FD) = $21) and ((reg = 4) or (reg = 5))) or {* MOV Rd,Dd / MOV Dd/Rd *} (((c and $FD) = $22) and ((reg = 1) or (reg = 5) or (reg = 6))) {* MOV Rd,Cd / MOV Cd/Rd *} ) then Exit; {$endif} end; {* modrm *} diza.flags := diza.flags or flags; // Copy code a := (flags shr 3) and 1; if ((flags and C_ADDR67) > 0) then Inc(a, addrsize); diza.addrsize := a; if (a > 0) then begin for i := 0 to (a - 1) do begin puint8_t(Longword(@diza.addr.addr1) + i)^ := p^; Inc(p); end; end; // Copy Data a := flags and 3; if ((flags and C_DATA66) > 0) then Inc(a, datasize); diza.datasize := a; if (a > 0) then begin for i := 0 to (a - 1) do begin puint8_t(Longword(@diza.data.data1) + i)^ := p^; Inc(p); end; end; {* check 3D Now suffix *} if ((diza.opcode = $0F) and (diza.opcode2 = $0F)) then begin i := diza.data.data1; if ((yad_data[YAD_3DNOW_OFFSET + (i shr 3)] and (1 shl (i and 7))) > 0) then Exit; end; {* check opcode length *} diza.len := (Longword(p) - Longword(opcode)); if (diza.len > 15) then Exit; Result := diza.len; end; function yad_asm(opcode: puint8_t; var diza: yad_t): Integer; stdcall; var i: Integer; p: puint8_t; begin p := opcode; for i := 0 to (5 - 1) do begin if (puint8_t(LongWord(diza.p_seg) + LongWord(i))^ > 0) then begin p^ := puint8_t(LongWord(diza.p_seg) + LongWord(i))^; Inc(p); end; end; p^ := diza.opcode; Inc(p); if (diza.opcode = $0F) then begin p^ := diza.opcode2; Inc(p); end; if ((diza.flags and C_MODRM) > 0) then begin p^ := diza.modrm; Inc(p); end; if ((diza.flags and C_SIB) > 0) then begin p^ := diza.sib; Inc(p); end; if (diza.addrsize > 0) then begin for i := 0 to (diza.addrsize - 1) do begin p^ := puint8_t(LongWord(@diza.addr.addr1) + LongWord(i))^; Inc(p); end; end; if (diza.datasize > 0) then begin for i := 0 to (diza.datasize - 1) do begin p^ := puint8_t(LongWord(@diza.data.data1) + LongWord(i))^; Inc(p); end; end; Result := LongWord(p) - LongWord(opcode); end; end.