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