이진 디스어셈블러를 쓰는 것은 실제로 바이너리 데이터의 패턴과 디코드 엔티티 간의 관계를 지정하려는 것을 의미합니다. 두 개의 명령어를 인식하면 겹치지 않는다고 가정하는 것이 합리적입니다.
종래의 파서는이 작업을 매우 잘 수행하지 않습니다. 개별 비트 또는 바이트를 토큰으로 가정하는 일련의 명령어에 대한 문법을 작성할 수 있지만, 여전히 인스턴스 작성 시퀀스 사이의 틈을 처리해야합니다.
내가 본 가장 현명한 접근 방식은 Norman Ramsey와 그의 팀에서 SLED라고하는 도구입니다.이 도구는 바이너리 데이터에 대한 간결한 패턴을 작성하고이를 바이너리 인코더와 디코더로 자동 어셈블 할 수있게합니다. 이 research paper discusses SLED 및 여러 유사한 시스템. 요점 : "파서 생성기"이상의 개념이지만 개념은 비슷합니다. 데이터를 설명하는 패턴이 많으며 패턴을 효율적인 엔진으로 조합하여 모두 일치시키는 코드 생성기입니다.
이러한 도구의 모양을 알려주기 위해 필자는이 영역에서 수행 한 일부 작업을 기반으로 한 부분적인 x86-64 인코딩 조각을 제공합니다. 아이디어는 결국 명령 정의를 작성할 수 있도록 작성한 명명 된 패턴 (제약 조건 포함)을 정의하는 것입니다. 여기에 작은 부분에 대한 간단한 샘플입니다 (모든 일이 몇 가지 1,200 선입니다) : 당신이 정말로 간단한 명령어 세트와 단지 간단한 가상 머신을 디코딩하는 경우
datatype SIB
{ ScaleSize: unsigned encoding { Times1=0 Times2=1 Times4=2 Times8=3} 2 bits
ScaledIndex: unsigned encoding { EAX=0 ECX=1 EDX=2 EBX=3 none=4 EBP=5 ESI=6 EDI=7 } 3 bits
IndexRegister: unsigned encoding { EAX=0 ECX=1 EDX=2 EBX=3 ESP=4 EBP,disp32=5 ESI=6 EDI=7 } 3 bits
}
encoding Grp1 { ADD=0 OR ADC SBB AND SUB XOR CMP }
encoding Grp1A { POP=0 * * * * * * * }
encoding Grp2 { ROL=0 ROR RCL RCR SHL,SAL SHR * SAR }
encoding Grp3 { TESTIbIz=0 * NOT NEG MULAX,MULrAX IMULAL,IMULrAX DIVAL,DIVrAX IDIVAL,IDIVrAX }
encoding Grp4 { INCEb=0 DECEb * * * * * * }
encoding Grp5 { INCEv=0 DECEv CALLNEv CALLFEp JMPNEv JMPFEp PUSHEv * }
encoding Grp6 { SLDTRvMW=0 STRRvMw LLDTEw LTREw VERREw VERWEw * * }
encoding Grp7mem { SGDTMs=0 SIDTMs LGDTMs LIDTMs SMSWMwRv * LMSWEw INVLPGMb }
encoding Grp7reg { VMCALL,VMLAUNCH,VMRESUME,VMXOFF=0 MONITOR,MWAIT * * SMSWMwRv * LMSWEw SWAPGS }
encoding Grp8 { *=0 * * * BT BTS BTR BTC }
encoding Grp9mem { * CMPXCH8BMq,CMPXCH16BMdq * * * * VMPTRLDMq,VMCLEARMq,VMXONMq VMPTRSTMq }
encoding Grp9reg { *=0 * * * * * * * }
encoding Grp10 { * * * * * * * }
encoding Grp11Ib { MOVEbIb * * * * * * * }
encoding Grp11Iz { MOVEvIz * * * * * * * }
encoding Grp12mem { * * * * * * * * }
encoding Grp12reg { *=0 * * PSRLWNqIb,PSRLWUdqIb * PSRAWNqIb,PSRAWUdqIb * PSLLWNqIb,PSLLWUdqIb * }
encoding Grp13mem { * * * * * * * * }
encoding Grp13reg { *=0 * * PSRLDNqIb,PSLRDUdqIb * PSRADNqIb,PSRADUdqIb * PSLLDNqIb,PSLLDUdqIb * }
encoding Grp14mem { * * * * * * * * }
encoding Grp14reg { *=0 * * PSRLQNqIb,PSRLQUdqIb PSRLDQUdqIb * * PSLLQNqIb,PSLLQUdqIb PSLLDQUDqIb }
encoding Grp15mem { FXSAVE=0 FXRSTOR LDMXCSR STMXCSR * * * CFLUSH }
encoding Grp15reg { *=0 * * * LFENCE MFENCE SFENCE }
encoding Grp16mem { PREFETCHNTA=0 PREFETCHT0 PREFETCHT1 PREFETCHT2 * * * }
encoding Grp16reg { * * * * * * * * }
...
instruction { ADCr64Immediate => Grp1.ADC
ADDr64Immediate => Grp1.ADD
ANDr64Immediate => Grp1.AND
CMPr64Immediate => Grp1.CMP
ORr64Immediate => Grp1.OR
SBBr64Immediate => Grp1.SBB
SUBr64Immediate => Grp1.SUB
XORr64Immediate => Grp1.XOR
}
(Target: Register32, Immediate: signed 32 bits)
BasicInstruction
& prefix_length0
& if Intel64 => prefix_REX(W=On R=Target:3)
& OneByteOpcode & Subcode=ImmGrp1EvIz
& ModRM(Mod=reg RSlashM=Target:2-0 reg=*)
, 어쩌면 당신은 모든 필요가 없습니다 "단순 VM"이 비트를 압축하거나 바이트 경계를 넘어 데이터를 분할하지 못하거나 이러한 가정을 위반하는 몇 가지 사례를 해킹 할 수 있기 때문에이 기능을 사용할 수 있습니다. 사람들의 VM이 점점 복잡해지면서 (수년에 걸쳐 진화하면서), VM은 점점 더 복잡해집니다. YMMV.
맞아요, 당신은 그 반대를해야합니다. 그러나 당신이 lexer + Yacc 조합으로 이것을 할 수 없다는 것은 사실이 아닙니다. 렉서에게 의미있는 입력을 제공하거나 문자 대신 바이트를 받아들이는 독자적인 렉서를 작성할 수 있도록 입력을 사전 처리해야합니다 (문자는 문자 세트를 기반으로 바이트 만 변환되었지만).읽은 모든 바이트는 나중에 받아 들일 수있는 입력이 무엇인지 그리고 얼마나 오래되었는지를 결정합니다. 따라서 비트가 설정되면 다른 바이트 값을 읽고 다른 상태에 있음을 의미합니다. – Ma3x
목적에 따라 구매 한 제품의 규칙 (최종 사용자 계약)에 위배 될 수 있습니다. 이것이 당신이 찾고있는 것인지 확실하지는 않지만 아이디어를 보려면 여기를보십시오 : https://github.com/ev3dev/lms-hacker-tools/blob/master/EV3/lmsdisasm.py – Ma3x
자바 클래스 파일 디스어셈블러를 썼습니다. Python (Krakatau)에서 도움이 될 것입니다. 어려운 부분이 무엇인지는 알 수 없습니다. 멋진 프레임 워크가 필요 없으며 원하는대로 코드를 작성하면됩니다. – Antimony