From 8df51c3d165c9c225e51d502b8816998f25ea2a2 Mon Sep 17 00:00:00 2001 From: Drahflow Date: Wed, 28 May 2014 00:21:19 +0200 Subject: Initial commit. --- samyle/cmdline.ey | 56 +++++++ samyle/decoder-tests.ey | 18 ++ samyle/decoder.ey | 423 +++++++++++++++++++++++++++++++++++++++++++++++ samyle/disasm.ey | 115 +++++++++++++ samyle/elf.ey | 117 +++++++++++++ samyle/hexedit.ey | 34 ++++ samyle/locations-test.ey | 6 + samyle/locations.ey | 24 +++ samyle/main.ey | 33 ++++ samyle/screens.ey | 15 ++ samyle/terminal.ey | 34 ++++ samyle/utils.ey | 39 +++++ samyle/welcome.ey | 16 ++ 13 files changed, 930 insertions(+) create mode 100644 samyle/cmdline.ey create mode 100644 samyle/decoder-tests.ey create mode 100644 samyle/decoder.ey create mode 100644 samyle/disasm.ey create mode 100644 samyle/elf.ey create mode 100644 samyle/hexedit.ey create mode 100644 samyle/locations-test.ey create mode 100644 samyle/locations.ey create mode 100644 samyle/main.ey create mode 100644 samyle/screens.ey create mode 100644 samyle/terminal.ey create mode 100644 samyle/utils.ey create mode 100644 samyle/welcome.ey diff --git a/samyle/cmdline.ey b/samyle/cmdline.ey new file mode 100644 index 0000000..c2282a2 --- /dev/null +++ b/samyle/cmdline.ey @@ -0,0 +1,56 @@ +< + terminal "$" via + sys .linux "+" via + + "" ==input + + { + "" =input + display + } /init deffd + + { ==k + 0 10 $goto 0 k * txt .produce .u $out + [ + { 0 k * 10 eq } { input execute init } + { 0 k * 127 eq } { 1 neg input str .prefix =input } + { 1 } { input k cat =input } + ] conds + display + } /handle deffd + + { _ ==cmd " " str .split =*args + [ + { cmd len 0 eq } { "No command specified." $err } + { 0 args "q" eq } { 0 =running } + { 0 args "r" eq } { + |args len 2 neq { "Use :r " $err } { + 1 args "\0" cat +ORDONLY 0 +open ==fd + fd 0 le { "Could not open file" $err } { + fd +fstat -- .size ==size + 0 size +PROTREAD +MAPPRIVATE fd 0 +mmap ==addr + "Loaded at address " addr txt .produce .hu cat $info + + addr locations .cursor .gotoByte + screens .|hexedit screens .enter + } ? * + } ? * + } + { 0 args "e" eq } { + |args len 2 neq { "Use :e " $err } { + 1 args elf .load + screens .|disasm screens .enter + } ? * + } + { 0 args "d" eq } { screens .|disasm screens .enter } + ] conds + } /execute deffd + + { + 0 25 $goto $clearLine ":" $out input $out + } /display deffd + + { _ "" eq |init |handle ? * } +> -- /cmdline deffd + +# vim: syn=elymas diff --git a/samyle/decoder-tests.ey b/samyle/decoder-tests.ey new file mode 100644 index 0000000..06a2056 --- /dev/null +++ b/samyle/decoder-tests.ey @@ -0,0 +1,18 @@ +txt .consume .|hu "%" defq + +[ ] =*memory + +< > /utils defvd + +"decoder.ey" include + +[ %31 %ED ] =memory # xor %ebp, %ebp + +0 decoder .fromAddress ==instr +instr .txt _ dump "xor %ebp, %ebp" eq assert +instr .partCount _ dump 4 eq assert +0 instr .txtPartSelect -12 -- _ dump "xor %ebp, %ebp" eq assert +1 instr .txtPartSelect -12 -- _ dump "xor" eq assert +2 instr .txtPartSelect -12 -- _ dump "%ebp" eq assert +3 instr .txtPartSelect -12 -- _ dump "%ebp" eq assert +4 instr .txtPartSelect -12 -- _ dump "" eq assert diff --git a/samyle/decoder.ey b/samyle/decoder.ey new file mode 100644 index 0000000..2a160d5 --- /dev/null +++ b/samyle/decoder.ey @@ -0,0 +1,423 @@ +< + utils "$$" via + txt .consume .|hu "%" defq + txt .produce "$>" via + sys .linux "+" via + + 0 ==:GPR + + { < + _ ==startA ==a + 0 ==prefix66 + 0 ==prefix67 + 0 ==operandWidth + 64 ==addressWidth + 0 ==rex + 0 ==rexW + 0 ==rexB + 0 ==rexR + 0 ==rexX + 1 neg ==rm + 1 neg ==reg + 1 neg ==mode + 1 neg ==dir + 1 neg ==imm + 1 neg ==target + 1 neg ==scale + 1 neg ==base + 1 neg ==idx + 0 ==hasDisp + 1 neg ==disp + 1 neg ==immWidth + 0 ==hasImmediate + "???" ==instruction + { [ instruction ] } /parts deffst + + { _ sys .typed .type 7 eq { |partsToTxt each } |cat ? * } /partsToTxt deffst + { "" parts partsToTxt } /txt deffst + + { _ sys .typed .type 7 eq { |partsToCount each 1 add } { -- } ? * } /partsToCount deffst + { 0 parts partsToCount } /partCount deffst + + { ==selected 0 ==any 0 ==p + { 0 ==sel _ sys .typed .type 7 eq { + selected p eq _ =sel { "" -01 1 =any } rep p 1 add =p |partsToTxtSelect each sel { "" } rep } |cat ? * + } /partsToTxtSelect deffst + "" parts partsToTxtSelect + any not { "" "" } rep + } /txtPartSelect deffst + + 1 ==prefixDecoding + { prefixDecoding 0 =prefixDecoding } { + a $$memory %66 eq { 1 =prefix66 a 1 add =a 1 =prefixDecoding } rep + a $$memory %67 eq { 1 =prefix67 a 1 add =a 1 =prefixDecoding } rep + } loop + + prefix67 { 32 =addressWidth } rep + + a $$memory %F0 band %40 eq { + a $$memory =rex + rex 1 band 1 0 ? =rexB + rex 2 band 1 0 ? =rexX + rex 4 band 1 0 ? =rexR + rex 8 band 1 0 ? =rexW + a 1 add =a + } rep + + { ==a + a $$memory ==sib + sib %07 band rexB 8 mul add =base + sib %38 band 8 div rexX 8 mul add =idx + sib %C0 band 64 div [ 1 2 4 8 ] * =scale + + idx 4 eq { 1 neg =idx } rep + idx 5 eq { 1 neg =base } rep + + a 1 add =a + a + } /decodeSib deffst + + { ==a + a $$memory ==modrm + modrm %07 band rexB 8 mul add _ =rm =base + modrm %38 band 8 div rexR 8 mul add =reg + modrm %C0 band 64 div =mode + a 1 add =a + + mode 3 eq { 1 neg =base } rep + + mode 3 neq rm 7 band 4 eq and { + a decodeSib =a + } rep + mode 2 eq { + a a 4 add range $$memory 256 math .unbase =disp 1 =hasDisp a 4 add =a + disp 2147483648 ge { disp 4294967296 neg bor =disp } rep + } rep + mode 1 eq { + a $$memory =disp 1 =hasDisp a 1 add =a + disp 128 ge { disp 256 neg bor =disp } rep + } rep + mode 0 eq rm 5 eq and { + a a 4 add range $$memory 256 math .unbase =disp 1 =hasDisp a 4 add =a + disp 2147483648 ge { disp 4294967296 neg bor =disp } rep + 16 =base + } rep + + a + } /decodeRegisterModrm deffst + + { ==width ==reg + [ + { 8 width eq } { reg [ /al /cl /dl /bl ] rex [ /spl /bpl /sil /dil ] [ /ah /ch /dh /bh ] ? cat + [ /r8l /r9l /r10l /r11l /r12l /r13l /r14l /r15l "??? [rip 8 bit]" ] cat * } + { 16 width eq } { reg [ /ax /cx /dx /bx /sp /bp /si /di /r8w /r9w /r10w /r11w /r12w /r13w /r14w /r15w "??? [rip 16 bit]" ] * } + { 32 width eq } { reg [ /eax /ecx /edx /ebx /esp /ebp /esi /edi /r8d /r9d /r10d /r11d /r12d /r13d /r14d /r15d "??? [rip 32 bit]" ] * } + { 64 width eq } { reg [ /rax /rcx /rdx /rbx /rsp /rbp /rsi /rdi /r8 /r9 /r10 /r11 /r12 /r13 /r14 /r15 /rip ] * } + { 1 } { "??? [gprName]" } + ] conds + } /gprName deffd + + { a startA sub } /length deffst + { [ [ instruction ] " " dir { gprRmParts ", " gprRegParts } { gprRegParts ", " gprRmParts } ? * ] } /gpi2opParts deffst + { [ "%" reg operandWidth gprName cat ] } /gprRegParts deffst + { [ + { mode 3 eq } { [ "%" rm operandWidth gprName cat ] } + { mode 3 lt } { [ + hasDisp { disp dispParts } rep + base 0 ge idx 0 ge or { "(" + base 0 ge { [ "%" base addressWidth gprName ] } rep + idx 0 ge { + ", " [ "%" idx addressWidth gprName ] + scale 1 neq { ", " [ scale $>u ] } rep + } rep + ")" } rep + ] } + { 1 } { "??? [rm]" } + ] conds } /gprRmParts deffst + { # ==n + _ [ -01 16 mod "0123456789abcdef" * ] str .fromArray + -01 16 div + } /extractHexDigit deffd + { ==n [ [ + { operandWidth 8 eq } { [ n 2 |extractHexDigit rep -- "$0x" ] reverse |cat fold } + { operandWidth 16 eq } { [ n 4 |extractHexDigit rep -- "$0x" ] reverse |cat fold } + { operandWidth 32 eq } { [ n 8 |extractHexDigit rep -- "$0x" ] reverse |cat fold } + { operandWidth 64 eq } { [ n 16 |extractHexDigit rep -- "$0x" ] reverse |cat fold } + { 1 } { "??? [immParts]" } + ] conds ] } /immParts deffst + { ==n [ [ + { addressWidth 8 eq } { [ n 2 |extractHexDigit rep -- "$0x" ] reverse |cat fold } + { addressWidth 16 eq } { [ n 4 |extractHexDigit rep -- "$0x" ] reverse |cat fold } + { addressWidth 32 eq } { [ n 8 |extractHexDigit rep -- "$0x" ] reverse |cat fold } + { addressWidth 64 eq } { [ n 16 |extractHexDigit rep -- "$0x" ] reverse |cat fold } + { 1 } { "??? [dispParts]" } + ] conds ] } /dispParts deffst + { [ + target $>hu _ locations .names .has { + _ " = " cat -01 locations .names * cat + } rep + ] } /targetParts deffst + + { + 32 =operandWidth + prefix66 { 16 =operandWidth } { } ? * + rex { 64 =operandWidth } { } ? * + + |gpi2opParts =parts + a decodeRegisterModrm =a + } /gpi2Op deffst + { + 8 =operandWidth + + |gpi2opParts =parts + a decodeRegisterModrm =a + } /gpi82Op deffst + { + 32 =operandWidth + prefix66 { 16 =operandWidth } { } ? * + rex { 64 =operandWidth } { } ? * + + { [ [ instruction ] " " gprRmParts ] } =parts + a decodeRegisterModrm =a + } /gpi1Op deffst + { + 32 =operandWidth + prefix66 { 16 =operandWidth } { } ? * + rex { 64 =operandWidth } { } ? * + + a decodeRegisterModrm =a 1 neg =reg # register field used to select opcodes + 1 =hasImmediate + a $$memory =imm a 1 add =a + { [ [ instruction ] " " imm immParts ", " gprRmParts ] } =parts + imm 128 ge { imm 256 neg bor =imm } rep + } /gpiImm8Op deffst + { + 8 =operandWidth + + a decodeRegisterModrm =a 1 neg =reg # register field used to select opcodes + 1 =hasImmediate + a $$memory =imm a 1 add =a + { [ [ instruction ] " " imm immParts ", " gprRmParts ] } =parts + imm 128 ge { imm 256 neg bor =imm } rep + } /gpi8ImmOp deffst + { + 32 =operandWidth + prefix66 { 16 =operandWidth } { } ? * + rex { 64 =operandWidth } { } ? * + + a decodeRegisterModrm =a 1 neg =reg # register field used to select opcodes + 1 =hasImmediate + operandWidth 64 eq 32 operandWidth ? =immWidth + a a immWidth 8 div add range $$memory 256 math .unbase =imm a immWidth 8 div add =a + { [ [ instruction ] " " imm immParts ", " gprRmParts ] } =parts + operandWidth 64 eq imm 2147483648 ge and { imm 4294967296 neg bor =imm } rep + } /gpiImmOp deffst + { + { [ [ instruction ] " " gprRegParts ] } =parts + 64 =operandWidth + } /popOp deffst + { + 32 =operandWidth + prefix66 { 16 =operandWidth } { } ? * + rex { 64 =operandWidth } { } ? * + + 1 =hasImmediate + operandWidth =immWidth + a a immWidth 8 div add range $$memory 256 math .unbase =imm a immWidth 8 div add =a + { [ [ instruction ] " " imm immParts ", " gprRegParts ] } =parts + } /movIOp deffst + { + 32 _ =operandWidth =immWidth + prefix66 { 16 _ =operandWidth =immWidth } { } ? * + rex { 64 =operandWidth } { } ? * + 0 =reg + + 1 =hasImmediate + a a immWidth 8 div add range $$memory 256 math .unbase =imm a immWidth 8 div add =a + immWidth 32 eq imm 2147483648 ge and { imm 4294967296 neg bor =imm } rep + immWidth 16 eq imm 32768 ge and { imm 65536 neg bor =imm } rep + { [ [ instruction ] " " imm immParts ", " gprRegParts ] } =parts + } /axImmOp deffst + { + 8 _ =operandWidth =immWidth + 0 =reg + + 1 =hasImmediate + a a immWidth 8 div add range $$memory 256 math .unbase =imm a immWidth 8 div add =a + imm 128 ge { imm 256 neg bor =imm } rep + { [ [ instruction ] " " imm immParts ", " gprRegParts ] } =parts + } /ax8ImmOp deffst + { + 64 =operandWidth + 32 =immWidth + prefix66 { 16 =immWidth } { } ? * + + a a immWidth 8 div add range $$memory 256 math .unbase =imm a immWidth 8 div add =a + immWidth 32 eq imm 2147483648 ge and { imm 4294967296 neg bor =imm } rep + immWidth 16 eq imm 32768 ge and { imm 65536 neg bor =imm } rep + { [ [ instruction ] " " targetParts ] } =parts + a imm add =target + } /callOp deffst + { + { [ instruction ] } =parts + } /trivialOp deffst + { + 64 =operandWidth + 8 =immWidth + a $$memory =imm a 1 add =a + imm 128 ge { imm 256 neg bor =imm } rep + { [ [ instruction ] " " targetParts ] } =parts + a imm add =target + } /jcc8Op deffst + + a $$memory ==opcode + a 1 add =a + a $$memory _ ==secondaryOpcode + %38 band 8 div ==modrmOpcode + a 1 add $$memory %38 band 8 div ==modrmOpcode2 + + [ + { opcode %00 eq } { "add" =instruction 0 =dir gpi82Op } + { opcode %01 eq } { "add" =instruction 0 =dir gpi2Op } + { opcode %02 eq } { "add" =instruction 1 =dir gpi82Op } + { opcode %03 eq } { "add" =instruction 1 =dir gpi2Op } + { opcode %04 eq } { "add" =instruction ax8ImmOp } + { opcode %05 eq } { "add" =instruction axImmOp } + { opcode %06 eq } { "push %es (invalid in 64bit)" trivialOp } + { opcode %07 eq } { "pop %es (invalid in 64bit)" trivialOp } + { opcode %08 eq } { "or" =instruction 0 =dir gpi82Op } + { opcode %09 eq } { "or" =instruction 0 =dir gpi2Op } + { opcode %0A eq } { "or" =instruction 1 =dir gpi82Op } + { opcode %0B eq } { "or" =instruction 1 =dir gpi2Op } + { opcode %0C eq } { "or" =instruction ax8ImmOp } + { opcode %0D eq } { "or" =instruction axImmOp } + { opcode %0E eq } { "push %cs (invalid in 64bit)" trivialOp } + { opcode %0F eq secondaryOpcode %1F eq and modrmOpcode2 0 eq and } { a 1 add =a "nop" =instruction gpi1Op } + # TODO insert secondary opcode map + + { opcode %10 eq } { "adc" =instruction 0 =dir gpi82Op } + { opcode %11 eq } { "adc" =instruction 0 =dir gpi2Op } + { opcode %12 eq } { "adc" =instruction 1 =dir gpi82Op } + { opcode %13 eq } { "adc" =instruction 1 =dir gpi2Op } + { opcode %14 eq } { "adc" =instruction ax8ImmOp } + { opcode %15 eq } { "adc" =instruction axImmOp } + { opcode %16 eq } { "push %ss (invalid in 64bit)" trivialOp } + { opcode %17 eq } { "pop %ss (invalid in 64bit)" trivialOp } + { opcode %18 eq } { "sbb" =instruction 0 =dir gpi82Op } + { opcode %19 eq } { "sbb" =instruction 0 =dir gpi2Op } + { opcode %1A eq } { "sbb" =instruction 1 =dir gpi82Op } + { opcode %1B eq } { "sbb" =instruction 1 =dir gpi2Op } + { opcode %1C eq } { "sbb" =instruction ax8ImmOp } + { opcode %1D eq } { "sbb" =instruction axImmOp } + { opcode %1E eq } { "push %ds (invalid in 64bit)" trivialOp } + { opcode %1F eq } { "pop %ds (invalid in 64bit)" trivialOp } + + { opcode %20 eq } { "and" =instruction 0 =dir gpi82Op } + { opcode %21 eq } { "and" =instruction 0 =dir gpi2Op } + { opcode %22 eq } { "and" =instruction 1 =dir gpi82Op } + { opcode %23 eq } { "and" =instruction 1 =dir gpi2Op } + { opcode %24 eq } { "and" =instruction ax8ImmOp } + { opcode %25 eq } { "and" =instruction axImmOp } + { opcode %26 eq } { "%es segment prefix (nop in 64bit)" trivialOp } + { opcode %27 eq } { "daa (invalid in 64bit)" trivialOp } + { opcode %28 eq } { "sub" =instruction 0 =dir gpi82Op } + { opcode %29 eq } { "sub" =instruction 0 =dir gpi2Op } + { opcode %2A eq } { "sub" =instruction 1 =dir gpi82Op } + { opcode %2B eq } { "sub" =instruction 1 =dir gpi2Op } + { opcode %2C eq } { "sub" =instruction ax8ImmOp } + { opcode %2D eq } { "sub" =instruction axImmOp } + { opcode %2E eq } { "%cs segment prefix (nop in 64bit)" trivialOp } + { opcode %2F eq } { "das (invalid in 64bit)" trivialOp } + + { opcode %30 eq } { "xor" =instruction 0 =dir gpi82Op } + { opcode %31 eq } { "xor" =instruction 0 =dir gpi2Op } + { opcode %32 eq } { "xor" =instruction 1 =dir gpi82Op } + { opcode %33 eq } { "xor" =instruction 1 =dir gpi2Op } + { opcode %34 eq } { "xor" =instruction ax8ImmOp } + { opcode %35 eq } { "xor" =instruction axImmOp } + { opcode %36 eq } { "%ss segment prefix (nop in 64bit)" trivialOp } + { opcode %37 eq } { "aaa (invalid in 64bit)" trivialOp } + { opcode %38 eq } { "cmp" =instruction 0 =dir gpi82Op } + { opcode %39 eq } { "cmp" =instruction 0 =dir gpi2Op } + { opcode %3A eq } { "cmp" =instruction 1 =dir gpi82Op } + { opcode %3B eq } { "cmp" =instruction 1 =dir gpi2Op } + { opcode %3C eq } { "cmp" =instruction ax8ImmOp } + { opcode %3D eq } { "cmp" =instruction axImmOp } + { opcode %3E eq } { "%ds segment prefix (nop in 64bit)" trivialOp } + { opcode %3F eq } { "aas (invalid in 64bit)" trivialOp } + + { opcode %50 eq } { "push" =instruction 0 rexR 8 mul add =reg popOp } + { opcode %51 eq } { "push" =instruction 1 rexR 8 mul add =reg popOp } + { opcode %52 eq } { "push" =instruction 2 rexR 8 mul add =reg popOp } + { opcode %53 eq } { "push" =instruction 3 rexR 8 mul add =reg popOp } + { opcode %54 eq } { "push" =instruction 4 rexR 8 mul add =reg popOp } + { opcode %55 eq } { "push" =instruction 5 rexR 8 mul add =reg popOp } + { opcode %56 eq } { "push" =instruction 6 rexR 8 mul add =reg popOp } + { opcode %57 eq } { "push" =instruction 7 rexR 8 mul add =reg popOp } + { opcode %58 eq } { "pop" =instruction 0 rexR 8 mul add =reg popOp } + { opcode %59 eq } { "pop" =instruction 1 rexR 8 mul add =reg popOp } + { opcode %5A eq } { "pop" =instruction 2 rexR 8 mul add =reg popOp } + { opcode %5B eq } { "pop" =instruction 3 rexR 8 mul add =reg popOp } + { opcode %5C eq } { "pop" =instruction 4 rexR 8 mul add =reg popOp } + { opcode %5D eq } { "pop" =instruction 5 rexR 8 mul add =reg popOp } + { opcode %5E eq } { "pop" =instruction 6 rexR 8 mul add =reg popOp } + { opcode %5F eq } { "pop" =instruction 7 rexR 8 mul add =reg popOp } + + { opcode %60 eq } { "pusha (invalid in 64bit)" =instruction trivialOp } + { opcode %61 eq } { "popa (invalid in 64bit)" =instruction trivialOp } + { opcode %62 eq } { "bound (invalid in 64bit)" =instruction trivialOp } + # TODO + + { opcode %70 eq } { "jo" =instruction jcc8Op } + { opcode %71 eq } { "jno" =instruction jcc8Op } + { opcode %72 eq } { "jc" =instruction jcc8Op } + { opcode %73 eq } { "jnc" =instruction jcc8Op } + { opcode %74 eq } { "jz" =instruction jcc8Op } + { opcode %75 eq } { "jnz" =instruction jcc8Op } + { opcode %76 eq } { "jbe" =instruction jcc8Op } + { opcode %77 eq } { "ja" =instruction jcc8Op } + { opcode %78 eq } { "js" =instruction jcc8Op } + { opcode %79 eq } { "jns" =instruction jcc8Op } + { opcode %7A eq } { "jp" =instruction jcc8Op } + { opcode %7B eq } { "jnp" =instruction jcc8Op } + { opcode %7C eq } { "jl" =instruction jcc8Op } + { opcode %7D eq } { "jge" =instruction jcc8Op } + { opcode %7E eq } { "jle" =instruction jcc8Op } + { opcode %7F eq } { "jg" =instruction jcc8Op } + + { opcode %80 eq modrmOpcode 7 eq and } { "cmp" =instruction gpi8ImmOp } + { opcode %83 eq modrmOpcode 0 eq and } { "add" =instruction gpiImm8Op } + { opcode %83 eq modrmOpcode 4 eq and } { "and" =instruction gpiImm8Op } + { opcode %83 eq modrmOpcode 5 eq and } { "sub" =instruction gpiImm8Op } + { opcode %83 eq modrmOpcode 7 eq and } { "cmp" =instruction gpiImm8Op } + { opcode %85 eq } { "test" =instruction 0 =dir gpi2Op } + { opcode %89 eq } { "mov" =instruction 0 =dir gpi2Op } + { opcode %8B eq } { "mov" =instruction 1 =dir gpi2Op } + { opcode %8D eq } { "lea" =instruction 1 =dir gpi2Op } + { opcode %B8 eq } { "mov" =instruction 0 rexR 8 mul add =reg movIOp } + { opcode %B9 eq } { "mov" =instruction 1 rexR 8 mul add =reg movIOp } + { opcode %BA eq } { "mov" =instruction 2 rexR 8 mul add =reg movIOp } + { opcode %BB eq } { "mov" =instruction 3 rexR 8 mul add =reg movIOp } + { opcode %BC eq } { "mov" =instruction 4 rexR 8 mul add =reg movIOp } + { opcode %BD eq } { "mov" =instruction 5 rexR 8 mul add =reg movIOp } + { opcode %BE eq } { "mov" =instruction 6 rexR 8 mul add =reg movIOp } + { opcode %BF eq } { "mov" =instruction 7 rexR 8 mul add =reg movIOp } + { opcode %C1 eq modrmOpcode 5 eq and } { "shr" =instruction gpiImm8Op } + { opcode %C1 eq modrmOpcode 7 eq and } { "sar" =instruction gpiImm8Op } + { opcode %C3 eq } { "ret" =instruction trivialOp } + { opcode %C6 eq modrmOpcode 0 eq and } { "mov" =instruction gpiImm8Op } + { opcode %C7 eq modrmOpcode 0 eq and } { "mov" =instruction gpiImmOp } + { opcode %C9 eq } { "leave" =instruction trivialOp } + { opcode %D1 eq modrmOpcode 5 eq and } { "shr" =instruction gpi1Op } + { opcode %D1 eq modrmOpcode 7 eq and } { "sar" =instruction gpi1Op } + { opcode %E8 eq } { "call" =instruction callOp } + { opcode %E9 eq } { "jmp" =instruction callOp } + { opcode %F3 eq } { "repz" =instruction trivialOp } + { opcode %F4 eq } { "hlt" =instruction trivialOp } + { opcode %FF eq modrmOpcode 2 eq and } { "call" =instruction gpi1Op operandWidth 32 eq { 64 =operandWidth } rep } + { opcode %FF eq modrmOpcode 4 eq and } { "jmp" =instruction gpi1Op operandWidth 32 eq { 64 =operandWidth } rep } + ] conds + > } /fromAddress deffd +> /decoder defvd + +# vim: syn=elymas diff --git a/samyle/disasm.ey b/samyle/disasm.ey new file mode 100644 index 0000000..234920d --- /dev/null +++ b/samyle/disasm.ey @@ -0,0 +1,115 @@ +< + terminal "$" via $styling "$:" via + utils "$$" via + locations .cursor "<>" via + sys .linux "+" via + txt .produce "$>" via + + 0 ==startAddr + 0 ==displayRecursion + + < + map ==cache + + { # ==addr + 1 sub 0 ==i + { _ $>hu cache .has not i 15 lt and } { 1 sub i 1 add =i } loop + } /prev deffd + + { _ ==addr $>hu ==addrTxt + addrTxt cache .has { addrTxt cache * } { + addr decoder .fromAddress _ addrTxt cache =[] + } ? * + } + > /instructions defvd /instrs deffd + + { + startAddr ==addr + 0 ==cursorOnScreen + + $clear + 1 ==y + { y 20 lt } { + addr instrs ==instr + <>byte addr eq { y =cursorOnScreen } rep + + 1 y $goto + addr $>hu _ locations .names .has { + { locations .names * $out } $:red + } { + $out + } ? <>byte addr eq <>column 0 eq and $:reverseIf + 30 y $goto + 0 instr .length range { ==i + { i addr add $$memory $$toHexSave " " cat $out } <>byte addr eq <>column 1 eq and <>elem i eq and $:reverseIf + } each + 60 y $goto + <>byte addr eq <>column 2 eq and { + <>elem instr .txtPartSelect -012 $out $reverse $out $normal $out + } { instr .txt $out } ? * + + instr .length addr add =addr + y 1 add =y + + 1 24 $goto + } loop + + cursorOnScreen not { <>byte =startAddr display } rep + cursorOnScreen 16 gt { startAddr _ instrs .length add =startAddr display } rep + } /draw deffd + + { + displayRecursion 1 add =displayRecursion + displayRecursion 4 gt { "Deep recursion in display" $err } |draw ? * + displayRecursion 1 sub =displayRecursion + } /display deffd + + { + "" ==currentInput + 1 ==running + { running } { + 1 sys .in .read ==k + [ + { 0 k * 10 eq } { 0 =running } + { 1 } { currentInput k _ $out cat =currentInput } + ] conds + } loop + currentInput + } /lineInput deffd + + { [ + { <>column 0 eq } { 0 22 $goto <>byte $>hu $out " => " $out lineInput <>byte $>hu locations .names =[] } + ] conds } /substituteElement deffd + + { [ + { <>column 0 eq } { 1 } + { <>column 1 eq } { <>byte instrs .length } + { <>column 2 eq } { <>byte instrs .partCount } + { 1 } { "??? [elemsInColumn]" $err 1 } + ] conds } /elemsInColumn deffd + + { ==k + { 0 -01 * } ":" deffst + + [ + { 0 k * :j eq } { <>byte _ instrs .length add <>gotoByte } + { 0 k * :k eq } { <>byte instructions .prev <>gotoByte } + { 0 k * :l eq } { + <>elem 1 add _ elemsInColumn lt { <>gotoElem } { + -- <>column 1 add 2 min <>gotoColumn 0 <>gotoElem + } ? * + } + { 0 k * :h eq } { + <>elem 1 sub _ 0 ge { <>gotoElem } { + -- <>column 1 sub 0 max _ <>gotoColumn elemsInColumn 1 sub <>gotoElem + } ? * + } + { 0 k * :s eq } |substituteElement + ] conds + display + } /handle deffd + + { _ "" eq |display |handle ? * } +> -- /disasm deffd + +# vim: syn=elymas diff --git a/samyle/elf.ey b/samyle/elf.ey new file mode 100644 index 0000000..7b57c94 --- /dev/null +++ b/samyle/elf.ey @@ -0,0 +1,117 @@ +< + terminal "$" via + utils "$$" via $$readMemory "=>" via + txt .produce "$>" via + sys .linux .ioctl "+" via + + { 1 sub 4096 div 1 add 4096 mul } /roundToPages deffd + { 4096 div 4096 mul } /pageStart deffd + + { ==addr + [ { addr $$memory _ } { addr 1 add =addr } loop -- ] str .fromArray + } /zeroTerminatedString deffd + + { + _ dump + "\0" cat +ORDONLY 0 +open ==fd + fd 0 le { "Could not open file" $err } { + fd +fstat -- .size ==size + 0 size +PROTREAD +MAPPRIVATE fd 0 +mmap ==addr + + 1 ==keepMapping + + [ + addr 0 add $$memory 127 eq + addr 1 add $$memory 0 "E" * eq + addr 2 add $$memory 0 "L" * eq + addr 3 add $$memory 0 "F" * eq + ] all not { "Not an ELF file" $err } { + addr 16 add =>u16 ==fileType + addr 24 add =>u64 ==entryPoint + addr 32 add =>u64 ==programHeaderOffset + addr 40 add =>u64 ==sectionHeaderOffset + addr 56 add =>u16 ==programHeaderCount + addr 60 add =>u16 ==sectionHeaderCount + addr 62 add =>u16 ==sectionNameStringTableIndex + + 1 ==:OBJECT + 2 ==:EXECUTABLE + + fileType EXECUTABLE eq { + 0 =keepMapping + + 0 programHeaderCount range { ==i + addr programHeaderOffset add i 56 mul add ==headerAddr + headerAddr =>u16 ==type + type 1 eq { + headerAddr 8 add =>u64 ==fileOffset + headerAddr 16 add =>u64 ==memoryAddress + headerAddr 32 add =>u64 ==sizeInFile + headerAddr 40 add =>u64 ==sizeInMemory + + memoryAddress pageStart _ ==mappingStart + memoryAddress sizeInMemory add mappingStart sub roundToPages + +PROTREAD +MAPPRIVATE +MAPFIXED bor fd fileOffset pageStart + +mmap 0 lt { ??io.mmap } rep + } rep + } each + } rep + + addr sectionHeaderOffset add sectionNameStringTableIndex 64 mul add 24 add =>u64 ==sectionNameStringTableOffset + + 0 sectionHeaderCount range { ==i + addr sectionHeaderOffset add i 64 mul add ==headerAddr + headerAddr =>u32 ==nameOffset + headerAddr 4 add =>u32 ==type + headerAddr 16 add =>u64 ==memoryAddress + headerAddr 24 add =>u64 ==fileOffset + headerAddr 32 add =>u64 ==size + headerAddr 40 add =>u32 ==linkedSection + + fileType EXECUTABLE eq { memoryAddress } { addr fileOffset add } ? * ==sectionAddress + sectionAddress 0 neq { + addr sectionNameStringTableOffset add nameOffset add zeroTerminatedString + sectionAddress $>hu + locations .names =[] + } rep + + type 11 eq type 2 eq or { + addr sectionHeaderOffset add linkedSection 64 mul add 24 add =>u64 ==symbolStringTableOffset + + 0 size 24 div range { ==j + addr fileOffset add j 24 mul add =>u32 ==symbolNameOffset + addr fileOffset add j 24 mul add 8 add =>u64 ==symbolAddress + fileType EXECUTABLE neq { addr symbolAddress add =symbolAddress } rep + + addr symbolStringTableOffset add symbolNameOffset add zeroTerminatedString + symbolAddress $>hu + locations .names =[] + } each + } rep + } each + + fileType EXECUTABLE eq { + "Loaded " + programHeaderCount txt .produce .u cat + " segments. Entry point at " cat + entryPoint txt .produce .hu cat + "." cat + } { + "Loaded " + sectionHeaderCount txt .produce .u cat + " sections." cat + } ? * $info + + [ + { fileType EXECUTABLE eq } { entryPoint } + { ".text" locations .namesReverse .has } { ".text" locations .namesReverse * txt .consume .hu } + { 1 } { 0 } + ] conds locations .cursor .gotoByte + } ? * + + keepMapping not { addr size +munmap -- } rep + } ? * + } /load deffd +> /elf defvd + +# vim: syn=elymas diff --git a/samyle/hexedit.ey b/samyle/hexedit.ey new file mode 100644 index 0000000..170c3eb --- /dev/null +++ b/samyle/hexedit.ey @@ -0,0 +1,34 @@ +< + terminal "$" via $styling "$:" via + utils "$$" via + locations .cursor "<>" via + + 1 neg ==CRAPFILE + + { + locations .cursor .byte _ ==addr 16 div 16 mul 128 sub ==base + + $clear + 0 16 range { ==y + 0 16 range { ==x + x 3 mul 1 add y 1 add $goto + + { $$memory $$toHexSave $out } base y 16 mul add x add _ addr eq $:reverseIf + } each + } each + } /display deffd + + { ==k + [ + { 0 k * 106 eq } { <>byte 16 add <>gotoByte } + { 0 k * 107 eq } { <>byte 16 sub <>gotoByte } + { 0 k * 108 eq } { <>byte 1 add <>gotoByte } + { 0 k * 104 eq } { <>byte 1 sub <>gotoByte } + ] conds + display + } /handle deffd + + { _ "" eq |display |handle ? * } +> -- /hexedit deffd + +# vim: syn=elymas diff --git a/samyle/locations-test.ey b/samyle/locations-test.ey new file mode 100644 index 0000000..69a4016 --- /dev/null +++ b/samyle/locations-test.ey @@ -0,0 +1,6 @@ +"locations.ey" include + +/someLabel /someAddr locations .names =[] + +/someAddr locations .names * _ dump "someLabel" eq assert +/someLabel locations .namesReverse * _ dump "someAddr" eq assert diff --git a/samyle/locations.ey b/samyle/locations.ey new file mode 100644 index 0000000..503af4e --- /dev/null +++ b/samyle/locations.ey @@ -0,0 +1,24 @@ +< + map /names defvd + + < + { ==v 0 + names dom { names * v eq or } each + } /has deffd + { ==v 0 ==found + names dom { _ ==k names * v eq found not and { k 1 =found } rep } each + } "#*" deffd + > /namesReverse defvd + + < + 0 ==byte + 0 ==column + 0 ==elem + + { =byte } /gotoByte deffd + { =column } /gotoColumn deffd + { =elem } /gotoElem deffd + > /cursor defvd +> /locations defvd + +# vim: syn=elymas diff --git a/samyle/main.ey b/samyle/main.ey new file mode 100644 index 0000000..3684bea --- /dev/null +++ b/samyle/main.ey @@ -0,0 +1,33 @@ +"utils.ey" include +"locations.ey" include +"terminal.ey" include +"screens.ey" include +"elf.ey" include +"decoder.ey" include + +# execute a function while setting the terminal to raw +{ # =*f + sys .linux .ioctl "+" via + 0 +tcgets -- + _ < _ .lflag +ICANON bnot band + +ECHO bnot band + ==lflag >' + { 0 -01 +tcsets -- } -10*3*20* +} /withRawTerminal deffd + +1 ==running + +{ + { running } { + 1 sys .in .read ==key + key ":" eq { + screens .|cmdline screens .enter + } { + key screens .current + } ? * + } loop +} /main deffd + +|main withRawTerminal + +# vim: syn=elymas diff --git a/samyle/screens.ey b/samyle/screens.ey new file mode 100644 index 0000000..4877f42 --- /dev/null +++ b/samyle/screens.ey @@ -0,0 +1,15 @@ +< + "welcome.ey" include + "cmdline.ey" include + "hexedit.ey" include + "disasm.ey" include + + { |current =last =current "" current } /enter deffd + { last =current } /exit deffd + + |welcome _ =*current + _ ==last + enter +> /screens defvd + +# vim: syn=elymas diff --git a/samyle/terminal.ey b/samyle/terminal.ey new file mode 100644 index 0000000..36d9327 --- /dev/null +++ b/samyle/terminal.ey @@ -0,0 +1,34 @@ +< + sys .out .|writeall '0. /out deffd + + { "\e[2J" out } /clear deffd + { "\e[2K" out } /clearLine deffd + { "\e[?25l" out } /cursorOff deffd + { "\e[?25h" out } /cursorOn deffd + + { "\e[0m" out } /normal deffd + + { deffd }' /defTerminal deffd + < { deffd }' > /styling defvd /defStyling deffd + + { ==name ==esc + { esc out } name defTerminal + { esc out * normal } name defStyling + { { esc out * normal } { * } ? * } name "If" cat defStyling + } /defStyle deffd + + "\e[1m" /bold defStyle + "\e[31m" /red defStyle + "\e[32m" /green defStyle + "\e[34m" /blue defStyle + "\e[7m" /reverse defStyle + + { ==y ==x + "\e[" y txt .produce .u cat ";" cat x txt .produce .u cat "H" cat out + } /goto deffd + + { ==s clear 40 s len 2 div sub 15 goto "\e[1;31;47;7m" out s out "\e[0m" out 1 sys .in .read -- clear } /err deffd + { ==s clear 40 s len 2 div sub 15 goto "\e[1;33;40;7m" out s out "\e[0m" out 1 sys .in .read -- clear } /info deffd +> /terminal defvd + +# vim: syn=elymas diff --git a/samyle/utils.ey b/samyle/utils.ey new file mode 100644 index 0000000..d0d5f32 --- /dev/null +++ b/samyle/utils.ey @@ -0,0 +1,39 @@ +< + sys .linux "+" via + + ".crap\0" +OWRONLY +OCREAT bor +OTRUNC bor 342 +open ==CRAPFILE + + { ==addr + CRAPFILE addr 1 +write ==err + + err 0 le { # EFAULT -> address not mapped + 1 neg + } { + addr sys .asm .peek + } ? * + } '0.0 /memory deffd + + < + { # ==addr + 0 2 range add memory + _ 1 neg eq any { -- ??io.invalid } { 256 math .unbase } ? * + } /u16 deffd + + { # ==addr + 0 4 range add memory + _ 1 neg eq any { -- ??io.invalid } { 256 math .unbase } ? * + } /u32 deffd + + { # ==addr + 0 8 range add memory + _ 1 neg eq any { -- ??io.invalid } { 256 math .unbase } ? * + } /u64 deffd + > /readMemory defvd + + # CRAPFILE +close + + { _ 16 div -01 16 mod "0123456789ABCDEF" [ -031*21* ] str .fromArray } '0.0 /toHex deffd + { _ 1 neg eq { -- "--" } |toHex ? * } '0.0 /toHexSave deffd +> /utils defvd + +# vim: syn=elymas diff --git a/samyle/welcome.ey b/samyle/welcome.ey new file mode 100644 index 0000000..3bf41a9 --- /dev/null +++ b/samyle/welcome.ey @@ -0,0 +1,16 @@ +< + terminal "$" via + + { $clear 0 0 $goto [ + "Welcome to samyle - the elymas reversing tool\n" + "\n" + "Many things should work similar to VIm, try :r for example\n" + ] $out } /greet deffd + + { + -- + greet + } +> -- /welcome deffd + +# vim: syn=elymas -- cgit v1.2.3