1 // copyright (c) 2019-2021 hors<horsicq@gmail.com>
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 
10 // The above copyright notice and this permission notice shall be included in all
11 // copies or substantial portions of the Software.
12 
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 // SOFTWARE.
20 //
21 #include "xcapstone.h"
22 
23 #if defined(_MSC_VER)
24 #if _MSC_VER > 1800
25 #pragma comment(lib, "legacy_stdio_definitions.lib") // vsprintf // TODO Check
26 #endif
27 #endif
28 
XCapstone(QObject * pParent)29 XCapstone::XCapstone(QObject *pParent) : QObject(pParent)
30 {
31 
32 }
33 
openHandle(XBinary::DM disasmMode,csh * pHandle,bool bDetails)34 cs_err XCapstone::openHandle(XBinary::DM disasmMode, csh *pHandle, bool bDetails)
35 {
36 //    printEnabledArchs();
37 
38     cs_err result=CS_ERR_HANDLE;
39 
40     if      (disasmMode==XBinary::DM_X86_16)        result=cs_open(CS_ARCH_X86,cs_mode(CS_MODE_16),pHandle);
41     else if (disasmMode==XBinary::DM_X86_32)        result=cs_open(CS_ARCH_X86,cs_mode(CS_MODE_32),pHandle);
42     else if (disasmMode==XBinary::DM_X86_64)        result=cs_open(CS_ARCH_X86,cs_mode(CS_MODE_64),pHandle);
43     else if (disasmMode==XBinary::DM_ARM_LE)        result=cs_open(CS_ARCH_ARM,cs_mode(CS_MODE_ARM|CS_MODE_LITTLE_ENDIAN),pHandle);
44     else if (disasmMode==XBinary::DM_ARM_BE)        result=cs_open(CS_ARCH_ARM,cs_mode(CS_MODE_ARM|CS_MODE_BIG_ENDIAN),pHandle);
45     else if (disasmMode==XBinary::DM_ARM64_LE)      result=cs_open(CS_ARCH_ARM64,cs_mode(CS_MODE_ARM|CS_MODE_LITTLE_ENDIAN),pHandle);
46     else if (disasmMode==XBinary::DM_ARM64_BE)      result=cs_open(CS_ARCH_ARM64,cs_mode(CS_MODE_ARM|CS_MODE_BIG_ENDIAN),pHandle);
47     else if (disasmMode==XBinary::DM_CORTEXM)       result=cs_open(CS_ARCH_ARM,cs_mode(CS_MODE_ARM|CS_MODE_THUMB|CS_MODE_MCLASS),pHandle);
48     else if (disasmMode==XBinary::DM_THUMB_LE)      result=cs_open(CS_ARCH_ARM,cs_mode(CS_MODE_ARM|CS_MODE_THUMB|CS_MODE_LITTLE_ENDIAN),pHandle);
49     else if (disasmMode==XBinary::DM_THUMB_BE)      result=cs_open(CS_ARCH_ARM,cs_mode(CS_MODE_ARM|CS_MODE_THUMB|CS_MODE_BIG_ENDIAN),pHandle);
50     else if (disasmMode==XBinary::DM_MIPS_LE)       result=cs_open(CS_ARCH_MIPS,cs_mode(CS_MODE_MIPS32|CS_MODE_LITTLE_ENDIAN),pHandle);
51     else if (disasmMode==XBinary::DM_MIPS_BE)       result=cs_open(CS_ARCH_MIPS,cs_mode(CS_MODE_MIPS32|CS_MODE_BIG_ENDIAN),pHandle);
52     else if (disasmMode==XBinary::DM_MIPS64_LE)     result=cs_open(CS_ARCH_MIPS,cs_mode(CS_MODE_MIPS64|CS_MODE_LITTLE_ENDIAN),pHandle);
53     else if (disasmMode==XBinary::DM_MIPS64_BE)     result=cs_open(CS_ARCH_MIPS,cs_mode(CS_MODE_MIPS64|CS_MODE_BIG_ENDIAN),pHandle);
54     else if (disasmMode==XBinary::DM_PPC_LE)        result=cs_open(CS_ARCH_PPC,cs_mode(CS_MODE_32|CS_MODE_LITTLE_ENDIAN),pHandle);
55     else if (disasmMode==XBinary::DM_PPC_BE)        result=cs_open(CS_ARCH_PPC,cs_mode(CS_MODE_32|CS_MODE_BIG_ENDIAN),pHandle);
56     else if (disasmMode==XBinary::DM_PPC64_LE)      result=cs_open(CS_ARCH_PPC,cs_mode(CS_MODE_64|CS_MODE_LITTLE_ENDIAN),pHandle);
57     else if (disasmMode==XBinary::DM_PPC64_BE)      result=cs_open(CS_ARCH_PPC,cs_mode(CS_MODE_64|CS_MODE_BIG_ENDIAN),pHandle);
58     else if (disasmMode==XBinary::DM_SPARC)         result=cs_open(CS_ARCH_SPARC,cs_mode(CS_MODE_BIG_ENDIAN),pHandle);
59     else if (disasmMode==XBinary::DM_S390X)         result=cs_open(CS_ARCH_SYSZ,cs_mode(CS_MODE_BIG_ENDIAN),pHandle);
60     else if (disasmMode==XBinary::DM_XCORE)         result=cs_open(CS_ARCH_XCORE,cs_mode(CS_MODE_BIG_ENDIAN),pHandle);
61     else if (disasmMode==XBinary::DM_M68K)          result=cs_open(CS_ARCH_M68K,cs_mode(CS_MODE_BIG_ENDIAN),pHandle);
62     else if (disasmMode==XBinary::DM_M68K40)        result=cs_open(CS_ARCH_M68K,cs_mode(CS_MODE_M68K_040),pHandle);
63     else if (disasmMode==XBinary::DM_TMS320C64X)    result=cs_open(CS_ARCH_TMS320C64X,cs_mode(CS_MODE_BIG_ENDIAN),pHandle);
64     else if (disasmMode==XBinary::DM_M6800)         result=cs_open(CS_ARCH_M680X,cs_mode(CS_MODE_M680X_6800),pHandle);
65     else if (disasmMode==XBinary::DM_M6801)         result=cs_open(CS_ARCH_M680X,cs_mode(CS_MODE_M680X_6801),pHandle);
66     else if (disasmMode==XBinary::DM_M6805)         result=cs_open(CS_ARCH_M680X,cs_mode(CS_MODE_M680X_6805),pHandle);
67     else if (disasmMode==XBinary::DM_M6808)         result=cs_open(CS_ARCH_M680X,cs_mode(CS_MODE_M680X_6808),pHandle);
68     else if (disasmMode==XBinary::DM_M6809)         result=cs_open(CS_ARCH_M680X,cs_mode(CS_MODE_M680X_6809),pHandle);
69     else if (disasmMode==XBinary::DM_M6811)         result=cs_open(CS_ARCH_M680X,cs_mode(CS_MODE_M680X_6811),pHandle);
70     else if (disasmMode==XBinary::DM_CPU12)         result=cs_open(CS_ARCH_M680X,cs_mode(CS_MODE_M680X_CPU12),pHandle);
71     else if (disasmMode==XBinary::DM_HD6301)        result=cs_open(CS_ARCH_M680X,cs_mode(CS_MODE_M680X_6301),pHandle);
72     else if (disasmMode==XBinary::DM_HD6309)        result=cs_open(CS_ARCH_M680X,cs_mode(CS_MODE_M680X_6309),pHandle);
73     else if (disasmMode==XBinary::DM_HCS08)         result=cs_open(CS_ARCH_M680X,cs_mode(CS_MODE_M680X_HCS08),pHandle);
74     else if (disasmMode==XBinary::DM_EVM)           result=cs_open(CS_ARCH_EVM,cs_mode(0),pHandle);
75     else if (disasmMode==XBinary::DM_RISKV32)       result=cs_open(CS_ARCH_RISCV,cs_mode(CS_MODE_RISCV32),pHandle);
76     else if (disasmMode==XBinary::DM_RISKV64)       result=cs_open(CS_ARCH_RISCV,cs_mode(CS_MODE_RISCV64),pHandle);
77     else if (disasmMode==XBinary::DM_RISKVC)        result=cs_open(CS_ARCH_RISCV,cs_mode(CS_MODE_RISCVC),pHandle);
78 //    else if (disasmMode==XBinary::DM_MOS65XX)       error=cs_open(CS_ARCH_M680X,cs_mode(CS_ARCH_MOS65XX),pHandle);
79 
80     if(result==CS_ERR_OK)
81     {
82         if(bDetails)
83         {
84             cs_option(*pHandle,CS_OPT_DETAIL,CS_OPT_ON);
85         }
86 
87         // TODO Syntax
88     }
89     else
90     {
91         *pHandle=0;
92     }
93 
94     return result;
95 }
96 
closeHandle(csh * pHandle)97 cs_err XCapstone::closeHandle(csh *pHandle)
98 {
99     cs_err result=CS_ERR_HANDLE;
100 
101     if(*pHandle)
102     {
103         result=cs_close(pHandle);
104         *pHandle=0;
105     }
106 
107     return result;
108 }
109 
disasm(csh handle,qint64 nAddress,char * pData,int nDataSize)110 XCapstone::DISASM_STRUCT XCapstone::disasm(csh handle, qint64 nAddress, char *pData, int nDataSize)
111 {
112     DISASM_STRUCT result={};
113 
114     cs_insn *pInsn=0;
115 
116     int nNumberOfOpcodes=cs_disasm(handle,(uint8_t *)pData,nDataSize,nAddress,1,&pInsn);
117     if(nNumberOfOpcodes>0)
118     {
119         result.nAddress=nAddress;
120         result.nSize=pInsn->size;
121 
122         QString sMnemonic=pInsn->mnemonic;
123         QString sStr=pInsn->op_str;
124 
125         result.sString+=sMnemonic;
126 
127         if(sStr!="") result.sString+=QString(" %1").arg(sStr);
128 
129         cs_free(pInsn,nNumberOfOpcodes);
130     }
131 
132     return result;
133 }
134 
isJmpOpcode(quint16 nOpcodeID)135 bool XCapstone::isJmpOpcode(quint16 nOpcodeID)
136 {
137     // TODO
138     bool bResult=false;
139 
140     if( (nOpcodeID==X86_INS_JMP)||
141         (nOpcodeID==X86_INS_JA)||
142         (nOpcodeID==X86_INS_JAE)||
143         (nOpcodeID==X86_INS_JB)||
144         (nOpcodeID==X86_INS_JBE)||
145         (nOpcodeID==X86_INS_JCXZ)||
146         (nOpcodeID==X86_INS_JE)||
147         (nOpcodeID==X86_INS_JECXZ)||
148         (nOpcodeID==X86_INS_JG)||
149         (nOpcodeID==X86_INS_JGE)||
150         (nOpcodeID==X86_INS_JL)||
151         (nOpcodeID==X86_INS_JLE)||
152         (nOpcodeID==X86_INS_JNE)||
153         (nOpcodeID==X86_INS_JNO)||
154         (nOpcodeID==X86_INS_JNP)||
155         (nOpcodeID==X86_INS_JNS)||
156         (nOpcodeID==X86_INS_JO)||
157         (nOpcodeID==X86_INS_JP)||
158         (nOpcodeID==X86_INS_JRCXZ)||
159         (nOpcodeID==X86_INS_JS)||
160         (nOpcodeID==X86_INS_LOOP)||
161         (nOpcodeID==X86_INS_LOOPE)||
162         (nOpcodeID==X86_INS_LOOPNE)||
163         (nOpcodeID==X86_INS_CALL))
164     {
165         bResult=true;
166     }
167 
168     return bResult;
169 }
170 
getSignature(QIODevice * pDevice,XBinary::_MEMORY_MAP * pMemoryMap,qint64 nAddress,ST signatureType,qint32 nCount)171 QString XCapstone::getSignature(QIODevice *pDevice, XBinary::_MEMORY_MAP *pMemoryMap, qint64 nAddress, ST signatureType, qint32 nCount)
172 {
173     QString sResult;
174 
175     csh handle=0;
176 
177     XBinary::DM disasmMode=XBinary::getDisasmMode(pMemoryMap);
178 
179     openHandle(disasmMode,&handle,true);
180 
181     if(handle)
182     {
183         while(nCount>0)
184         {
185             qint64 nOffset=XBinary::addressToOffset(pMemoryMap,nAddress);
186 
187             if(nOffset==-1)
188             {
189                 break;
190             }
191 
192             QByteArray baData=XBinary::read_array(pDevice,nOffset,15);
193 
194             cs_insn *pInsn=0;
195 
196             int nNumberOfOpcodes=cs_disasm(handle,(uint8_t *)baData.data(),15,nAddress,1,&pInsn);
197 
198             if(nNumberOfOpcodes>0)
199             {
200                 quint32 nDispOffset=0;
201                 quint32 nDispSize=0;
202                 quint32 nImmOffset=0;
203                 quint32 nImmSize=0;
204 
205                 if(XBinary::getDisasmFamily(disasmMode)==XBinary::DMFAMILY_X86)
206                 {
207                     nDispOffset=pInsn->detail->x86.encoding.disp_offset;
208                     nDispSize=pInsn->detail->x86.encoding.disp_size;
209                     nImmOffset=pInsn->detail->x86.encoding.imm_offset;
210                     nImmSize=pInsn->detail->x86.encoding.imm_size;
211                 }
212 
213                 baData.resize(pInsn->size);
214 
215                 QString sHEX=baData.toHex().data();
216 
217                 if((signatureType==ST_FULL)||(signatureType==ST_MASK))
218                 {
219                     nAddress+=pInsn->size;
220 
221                     if(signatureType==ST_MASK)
222                     {
223                         if(nDispSize)
224                         {
225                             sHEX=replaceWild(sHEX,nDispOffset,nDispSize,'.');
226                         }
227 
228                         if(nImmSize)
229                         {
230                             sHEX=replaceWild(sHEX,nImmOffset,nImmSize,'.');
231                         }
232                     }
233                 }
234                 else if(signatureType==ST_MASKREL)
235                 {
236                     if(isJmpOpcode(pInsn->id))
237                     {
238                         // TODO another archs
239                         if(XBinary::getDisasmFamily(disasmMode)==XBinary::DMFAMILY_X86)
240                         {
241                             for(int i=0; i<pInsn->detail->x86.op_count; i++)
242                             {
243                                 if(pInsn->detail->x86.operands[i].type==X86_OP_IMM) // TODO another archs !!!
244                                 {
245                                     qint64 nImm=pInsn->detail->x86.operands[i].imm;
246 
247                                     nAddress=nImm;
248 
249                                     sHEX=replaceWild(sHEX,nImmOffset,nImmSize,'$');
250                                 }
251                             }
252                         }
253                         else
254                         {
255                             nAddress+=pInsn->size;
256                         }
257                     }
258                     else
259                     {
260                         nAddress+=pInsn->size;
261                     }
262                 }
263 
264                 sResult+=sHEX;
265 
266                 cs_free(pInsn,nNumberOfOpcodes);
267             }
268             else
269             {
270                 break;
271             }
272 
273             nCount--;
274         }
275 
276         closeHandle(&handle);
277     }
278 
279     return sResult;
280 }
281 
replaceWild(QString sString,qint32 nOffset,qint32 nSize,QChar cWild)282 QString XCapstone::replaceWild(QString sString, qint32 nOffset, qint32 nSize, QChar cWild)
283 {
284     QString sResult=sString;
285     QString sWild;
286 
287     sWild=sWild.fill(cWild,nSize*2);
288 
289     sResult=sResult.replace(nOffset*2,nSize*2,sWild);
290 
291     return sResult;
292 }
293 
printEnabledArchs()294 void XCapstone::printEnabledArchs()
295 {
296     if(cs_support(CS_ARCH_ARM))         qDebug("CS_ARCH_ARM");
297     if(cs_support(CS_ARCH_ARM64))       qDebug("CS_ARCH_ARM64");
298     if(cs_support(CS_ARCH_MIPS))        qDebug("CS_ARCH_MIPS");
299     if(cs_support(CS_ARCH_X86))         qDebug("CS_ARCH_X86");
300     if(cs_support(CS_ARCH_PPC))         qDebug("CS_ARCH_PPC");
301     if(cs_support(CS_ARCH_SPARC))       qDebug("CS_ARCH_SPARC");
302     if(cs_support(CS_ARCH_SYSZ))        qDebug("CS_ARCH_SYSZ");
303     if(cs_support(CS_ARCH_XCORE))       qDebug("CS_ARCH_XCORE");
304     if(cs_support(CS_ARCH_M68K))        qDebug("CS_ARCH_M68K");
305     if(cs_support(CS_ARCH_TMS320C64X))  qDebug("CS_ARCH_TMS320C64X");
306     if(cs_support(CS_ARCH_M680X))       qDebug("CS_ARCH_M680X");
307     if(cs_support(CS_ARCH_EVM))         qDebug("CS_ARCH_EVM");
308     if(cs_support(CS_ARCH_MOS65XX))     qDebug("CS_ARCH_MOS65XX");
309     if(cs_support(CS_ARCH_WASM))        qDebug("CS_ARCH_WASM");
310     if(cs_support(CS_ARCH_BPF))         qDebug("CS_ARCH_BPF");
311     if(cs_support(CS_ARCH_RISCV))       qDebug("CS_ARCH_RISCV");
312 }
313 #ifdef QT_GUI_LIB
getOpcodeColorMap(XBinary::DM disasmMode)314 QMap<QString, QColor> XCapstone::getOpcodeColorMap(XBinary::DM disasmMode)
315 {
316     QMap<QString, QColor> mapResult;
317 
318     if(XBinary::getDisasmFamily(disasmMode)==XBinary::DMFAMILY_X86)
319     {
320         mapResult.insert("call",Qt::red);
321         mapResult.insert("ret",Qt::red);
322 
323         mapResult.insert("push",Qt::blue);
324         mapResult.insert("pop",Qt::blue);
325 
326         mapResult.insert("je",Qt::green);
327         mapResult.insert("jne",Qt::green);
328         mapResult.insert("jz",Qt::green);
329         mapResult.insert("jnz",Qt::green);
330         mapResult.insert("ja",Qt::green);
331         // TODO more
332     }
333 
334     return mapResult;
335 }
336 #endif
337