1 : // Copyright 2012 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/core/disassembler_util.h"
16 :
17 : #include "base/basictypes.h"
18 : #include "base/logging.h"
19 : #include "gmock/gmock.h"
20 : #include "gtest/gtest.h"
21 :
22 : namespace core {
23 :
24 : namespace {
25 :
26 : // Decompose a block of code using distorm wrapper.
27 : _DecodeResult DecomposeCode(const uint8* code_data,
28 : size_t length,
29 : _DInst result[],
30 : const unsigned int max_results,
31 E : unsigned int* result_count) {
32 E : _CodeInfo code = {};
33 E : code.dt = Decode32Bits;
34 E : code.features = DF_NONE;
35 E : code.codeOffset = 0;
36 E : code.codeLen = length;
37 E : code.code = code_data;
38 E : return DistormDecompose(&code, result, max_results, result_count);
39 E : }
40 :
41 : // Decompose a block of code using distorm directly.
42 : _DecodeResult RawDecomposeCode(const uint8* code_data,
43 : size_t length,
44 : _DInst result[],
45 : const unsigned int max_results,
46 E : unsigned int* result_count) {
47 E : _CodeInfo code = {};
48 E : code.dt = Decode32Bits;
49 E : code.features = DF_NONE;
50 E : code.codeOffset = 0;
51 E : code.codeLen = length;
52 E : code.code = code_data;
53 E : return distorm_decompose(&code, result, max_results, result_count);
54 E : }
55 :
56 E : _DInst DecodeBuffer(const uint8* buffer, size_t length) {
57 E : _DInst inst = {};
58 E : EXPECT_TRUE(DecodeOneInstruction(buffer, length, &inst));
59 E : EXPECT_EQ(length, inst.size);
60 E : return inst;
61 E : }
62 :
63 : // One of the AVX instructions that is currently not supported by distorm.
64 : // vxorps ymm0, ymm0, ymm0
65 : const uint8 kVxorps[] = { 0xC5, 0xFC, 0x57, 0xC0 };
66 :
67 : // Instructions for which distorm indicates a size of 0 for the destination
68 : // operand size.
69 : // fnstcw m16
70 : const uint8 kFnstcw[] = { 0xD9, 0x7D, 0xEA };
71 : // fldcw m16
72 : const uint8 kFldcw[] = { 0xD9, 0x6D, 0xE4 };
73 :
74 : // Instructions for which distorm do not activated the write flag.
75 : // fst qword ptr [0A374E8h]
76 : const uint8 kFst[] = { 0xDD, 0x15, 0xE8, 0x74, 0xA3, 0x00 };
77 : // fstp qword ptr [0A374E8h]
78 : const uint8 kFstp[] = { 0xDD, 0x1D, 0xE8, 0x74, 0xA3, 0x00 };
79 : // fist qword ptr [0A374E8h]
80 : const uint8 kFist[] = { 0xDB, 0x15, 0xE0, 0x74, 0xA3, 0x00 };
81 : // fistp qword ptr [0A374E8h]
82 : const uint8 kFistp[] = { 0xDB, 0x1D, 0xE0, 0x74, 0xA3, 0x00 };
83 :
84 : // Nop Instruction byte sequences.
85 : const uint8 kNop2Mov[] = { 0x8B, 0xFF };
86 : const uint8 kNop3Lea[] = { 0x8D, 0x49, 0x00 };
87 : const uint8 kNop1[] = { 0x90 };
88 : const uint8 kNop2[] = { 0x66, 0x90 };
89 : const uint8 kNop3[] = { 0x66, 0x66, 0x90 };
90 : const uint8 kNop4[] = { 0x0F, 0x1F, 0x40, 0x00 };
91 : const uint8 kNop5[] = { 0x0F, 0x1F, 0x44, 0x00, 0x00 };
92 : const uint8 kNop6[] = { 0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00 };
93 : const uint8 kNop7[] = { 0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00 };
94 : const uint8 kNop8[] = { 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
95 : const uint8 kNop9[] = {
96 : 0x66, // Prefix,
97 : 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 // kNop8.
98 : };
99 : const uint8 kNop10[] = {
100 : 0x66, 0x66, // Prefix.
101 : 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 // kNop8.
102 : };
103 : const uint8 kNop11[] = {
104 : 0x66, 0x66, 0x66, // Prefix.
105 : 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 // kNop8
106 : };
107 :
108 : // Call instruction.
109 : const uint8 kCall[] = { 0xE8, 0xCA, 0xFE, 0xBA, 0xBE };
110 :
111 : // Control Flow byte sequences (note that the JMP is indirect).
112 : const uint8 kJmp[] = { 0xFF, 0x24, 0x8D, 0xCA, 0xFE, 0xBA, 0xBE };
113 : const uint8 kRet[] = { 0xC3 };
114 : const uint8 kRetN[] = { 0xC2, 0x08, 0x00 };
115 : const uint8 kJe[] = { 0x74, 0xCA };
116 : const uint8 kSysEnter[] = { 0x0F, 0x34 };
117 : const uint8 kSysExit[] = { 0x0F, 0x35 };
118 :
119 : // Interrupts.
120 : const uint8 kInt2[] = { 0xCD, 0x02 };
121 : const uint8 kInt3[] = { 0xCC };
122 :
123 : // Improperly handled instructions.
124 : const uint8 kVpermq[] = { 0xC4, 0xE3, 0xFD, 0x00, 0xED, 0x44 };
125 : const uint8 kVpermd[] = { 0xC4, 0xE2, 0x4D, 0x36, 0xC0 };
126 :
127 E : void TestBadlyDecodedInstruction(const uint8* code, size_t code_length) {
128 E : _DInst inst[1] = {};
129 E : unsigned int inst_count = 0;
130 : _DecodeResult result = RawDecomposeCode(
131 E : code, code_length, inst, arraysize(inst), &inst_count);
132 E : EXPECT_EQ(DECRES_MEMORYERR, result);
133 E : EXPECT_EQ(0u, inst_count);
134 :
135 : result = DecomposeCode(
136 E : code, code_length, inst, arraysize(inst), &inst_count);
137 E : EXPECT_EQ(DECRES_SUCCESS, result);
138 E : EXPECT_EQ(1u, inst_count);
139 E : EXPECT_EQ(code_length, inst[0].size);
140 E : }
141 :
142 : } // namespace
143 :
144 E : TEST(DisassemblerUtilTest, DistormWrapperVxorpsPasses) {
145 E : _DInst inst = {};
146 E : EXPECT_TRUE(DecodeOneInstruction(kVxorps, sizeof(kVxorps), &inst));
147 E : }
148 :
149 E : TEST(DisassemblerUtilTest, InstructionToString) {
150 E : _DInst inst = {};
151 E : inst = DecodeBuffer(kNop1, sizeof(kNop1));
152 :
153 E : std::string Nop1Str;
154 E : EXPECT_TRUE(InstructionToString(inst, kNop1, sizeof(kNop1), &Nop1Str));
155 E : ASSERT_THAT(Nop1Str, testing::HasSubstr("90"));
156 E : ASSERT_THAT(Nop1Str, testing::HasSubstr("NOP"));
157 E : }
158 :
159 E : TEST(DisassemblerUtilTest, IsNop) {
160 E : EXPECT_FALSE(IsNop(DecodeBuffer(kJmp, sizeof(kJmp))));
161 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop1, sizeof(kNop1))));
162 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop2, sizeof(kNop2))));
163 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop3, sizeof(kNop3))));
164 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop4, sizeof(kNop4))));
165 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop5, sizeof(kNop5))));
166 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop6, sizeof(kNop6))));
167 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop7, sizeof(kNop7))));
168 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop8, sizeof(kNop8))));
169 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop9, sizeof(kNop9))));
170 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop10, sizeof(kNop10))));
171 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop11, sizeof(kNop11))));
172 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop2Mov, sizeof(kNop2Mov))));
173 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop3Lea, sizeof(kNop3Lea))));
174 E : }
175 :
176 E : TEST(DisassemblerUtilTest, IsCall) {
177 E : EXPECT_FALSE(IsCall(DecodeBuffer(kJmp, sizeof(kJmp))));
178 E : EXPECT_FALSE(IsCall(DecodeBuffer(kNop1, sizeof(kNop1))));
179 E : EXPECT_TRUE(IsCall(DecodeBuffer(kCall, sizeof(kCall))));
180 E : }
181 :
182 E : TEST(DisassemblerUtilTest, IsSystemCall) {
183 E : EXPECT_FALSE(IsSystemCall(DecodeBuffer(kJmp, sizeof(kJmp))));
184 E : EXPECT_FALSE(IsSystemCall(DecodeBuffer(kNop1, sizeof(kNop1))));
185 E : EXPECT_TRUE(IsSystemCall(DecodeBuffer(kSysEnter, sizeof(kSysEnter))));
186 E : EXPECT_TRUE(IsSystemCall(DecodeBuffer(kSysExit, sizeof(kSysExit))));
187 E : }
188 :
189 E : TEST(DisassemblerUtilTest, IsConditionalBranch) {
190 E : EXPECT_FALSE(IsConditionalBranch(DecodeBuffer(kNop4, sizeof(kNop4))));
191 E : EXPECT_FALSE(IsConditionalBranch(DecodeBuffer(kJmp, sizeof(kJmp))));
192 E : EXPECT_FALSE(IsConditionalBranch(DecodeBuffer(kRet, sizeof(kRet))));
193 E : EXPECT_TRUE(IsConditionalBranch(DecodeBuffer(kJe, sizeof(kJe))));
194 E : }
195 :
196 E : TEST(DisassemblerUtilTest, IsUnconditionalBranch) {
197 E : EXPECT_FALSE(IsUnconditionalBranch(DecodeBuffer(kNop4, sizeof(kNop4))));
198 E : EXPECT_FALSE(IsUnconditionalBranch(DecodeBuffer(kRet, sizeof(kRet))));
199 E : EXPECT_FALSE(IsUnconditionalBranch(DecodeBuffer(kJe, sizeof(kJe))));
200 E : EXPECT_TRUE(IsUnconditionalBranch(DecodeBuffer(kJmp, sizeof(kJmp))));
201 E : }
202 :
203 E : TEST(DisassemblerUtilTest, IsBranch) {
204 E : EXPECT_FALSE(IsBranch(DecodeBuffer(kNop4, sizeof(kNop4))));
205 E : EXPECT_FALSE(IsBranch(DecodeBuffer(kRet, sizeof(kRet))));
206 E : EXPECT_TRUE(IsBranch(DecodeBuffer(kJe, sizeof(kJe))));
207 E : EXPECT_TRUE(IsBranch(DecodeBuffer(kJmp, sizeof(kJmp))));
208 E : }
209 :
210 E : TEST(DisassemblerUtilTest, HasPcRelativeOperand) {
211 E : EXPECT_FALSE(HasPcRelativeOperand(DecodeBuffer(kRetN, sizeof(kRet)), 0));
212 E : EXPECT_FALSE(HasPcRelativeOperand(DecodeBuffer(kJmp, sizeof(kJmp)), 0));
213 E : EXPECT_TRUE(HasPcRelativeOperand(DecodeBuffer(kJe, sizeof(kJe)), 0));
214 E : }
215 :
216 E : TEST(DisassemblerUtilTest, IsControlFlow) {
217 E : EXPECT_FALSE(IsControlFlow(DecodeBuffer(kNop4, sizeof(kNop4))));
218 E : EXPECT_TRUE(IsControlFlow(DecodeBuffer(kJmp, sizeof(kJmp))));
219 E : EXPECT_TRUE(IsControlFlow(DecodeBuffer(kRet, sizeof(kRet))));
220 E : EXPECT_TRUE(IsControlFlow(DecodeBuffer(kRetN, sizeof(kRetN))));
221 E : EXPECT_TRUE(IsControlFlow(DecodeBuffer(kJe, sizeof(kJe))));
222 E : EXPECT_TRUE(IsControlFlow(DecodeBuffer(kSysEnter, sizeof(kSysEnter))));
223 E : }
224 :
225 E : TEST(DisassemblerUtilTest, IsImplicitControlFlow) {
226 E : EXPECT_FALSE(IsImplicitControlFlow(DecodeBuffer(kJe, sizeof(kJe))));
227 E : EXPECT_TRUE(IsImplicitControlFlow(DecodeBuffer(kRet, sizeof(kRet))));
228 E : EXPECT_TRUE(IsImplicitControlFlow(DecodeBuffer(kRetN, sizeof(kRetN))));
229 E : EXPECT_TRUE(IsImplicitControlFlow(DecodeBuffer(kJmp, sizeof(kJmp))));
230 E : }
231 :
232 E : TEST(DisassemblerUtilTest, IsInterrupt) {
233 E : EXPECT_FALSE(IsInterrupt(DecodeBuffer(kJe, sizeof(kJe))));
234 E : EXPECT_TRUE(IsInterrupt(DecodeBuffer(kInt2, sizeof(kInt2))));
235 E : EXPECT_TRUE(IsInterrupt(DecodeBuffer(kInt3, sizeof(kInt3))));
236 E : }
237 :
238 E : TEST(DisassemblerUtilTest, IsDebugInterrupt) {
239 E : EXPECT_FALSE(IsDebugInterrupt(DecodeBuffer(kJe, sizeof(kJe))));
240 E : EXPECT_FALSE(IsDebugInterrupt(DecodeBuffer(kInt2, sizeof(kInt2))));
241 E : EXPECT_TRUE(IsDebugInterrupt(DecodeBuffer(kInt3, sizeof(kInt3))));
242 E : }
243 :
244 E : TEST(DisassemblerUtilTest, GetRegisterType) {
245 E : EXPECT_EQ(R_DL, GetRegisterType(core::kRegisterDl));
246 E : EXPECT_EQ(R_AX, GetRegisterType(core::kRegisterAx));
247 E : EXPECT_EQ(R_EDI, GetRegisterType(core::kRegisterEdi));
248 :
249 E : EXPECT_EQ(R_BH, GetRegisterType(core::bh));
250 E : EXPECT_EQ(R_CX, GetRegisterType(core::cx));
251 E : EXPECT_EQ(R_ESP, GetRegisterType(core::esp));
252 E : }
253 :
254 E : TEST(DisassemblerUtilTest, GetRegisterId) {
255 E : EXPECT_EQ(kRegisterAl, GetRegisterId(R_AL));
256 E : EXPECT_EQ(kRegisterSp, GetRegisterId(R_SP));
257 E : EXPECT_EQ(kRegisterEdi, GetRegisterId(R_EDI));
258 E : }
259 :
260 E : TEST(DisassemblerUtilTest, GetRegister) {
261 E : EXPECT_EQ(core::bh, GetRegister(R_BH));
262 E : EXPECT_EQ(core::cx, GetRegister(R_CX));
263 E : EXPECT_EQ(core::ebp, GetRegister(R_EBP));
264 E : }
265 :
266 E : TEST(DisassemblerUtilTest, DistormDecompose) {
267 E : const unsigned int kMaxResults = 16;
268 E : unsigned int result_count = 0;
269 : _DInst results[kMaxResults];
270 : EXPECT_EQ(DECRES_SUCCESS,
271 : DecomposeCode(kNop3Lea,
272 : sizeof(kNop3Lea),
273 : results,
274 : kMaxResults,
275 E : &result_count));
276 E : EXPECT_EQ(1U, result_count);
277 E : EXPECT_EQ(32U, results[0].ops[0].size);
278 E : }
279 :
280 E : TEST(DisassemblerUtilTest, DistormDecomposeFnstcw) {
281 E : const unsigned int kMaxResults = 16;
282 E : unsigned int result_count = 0;
283 : _DInst results[kMaxResults];
284 : EXPECT_EQ(DECRES_SUCCESS,
285 : DecomposeCode(kFnstcw,
286 : sizeof(kFnstcw),
287 : results,
288 : kMaxResults,
289 E : &result_count));
290 E : EXPECT_EQ(1U, result_count);
291 E : EXPECT_EQ(16U, results[0].ops[0].size);
292 E : }
293 :
294 E : TEST(DisassemblerUtilTest, WrongAccessSizeOnRawDistormDecomposeFnstcw) {
295 E : const unsigned int kMaxResults = 16;
296 E : unsigned int result_count = 0;
297 : _DInst results[kMaxResults];
298 : EXPECT_EQ(DECRES_SUCCESS,
299 : RawDecomposeCode(kFldcw,
300 : sizeof(kFldcw),
301 : results,
302 : kMaxResults,
303 E : &result_count));
304 E : EXPECT_EQ(1U, result_count);
305 E : EXPECT_EQ(0U, results[0].ops[0].size);
306 E : }
307 :
308 E : TEST(DisassemblerUtilTest, DistormDecomposeFldcw) {
309 E : const unsigned int kMaxResults = 16;
310 E : unsigned int result_count = 0;
311 : _DInst results[kMaxResults];
312 : EXPECT_EQ(DECRES_SUCCESS,
313 : DecomposeCode(kFldcw,
314 : sizeof(kFldcw),
315 : results,
316 : kMaxResults,
317 E : &result_count));
318 E : EXPECT_EQ(1U, result_count);
319 E : EXPECT_EQ(16U, results[0].ops[0].size);
320 E : }
321 :
322 E : TEST(DisassemblerUtilTest, WrongAccessSizeOnRawDistormDecomposeFldcw) {
323 E : const unsigned int kMaxResults = 16;
324 E : unsigned int result_count = 0;
325 : _DInst results[kMaxResults];
326 : EXPECT_EQ(DECRES_SUCCESS,
327 : RawDecomposeCode(kFldcw,
328 : sizeof(kFldcw),
329 : results,
330 : kMaxResults,
331 E : &result_count));
332 E : EXPECT_EQ(1U, result_count);
333 E : EXPECT_EQ(0U, results[0].ops[0].size);
334 E : }
335 :
336 E : TEST(DisassemblerUtilTest, WrongWriteFlagOnRawDistormDecomposeFst) {
337 E : _DInst fst = DecodeBuffer(kFst, sizeof(kFst));
338 E : EXPECT_NE(0, fst.flags & FLAG_DST_WR);
339 :
340 E : _DInst fstp = DecodeBuffer(kFstp, sizeof(kFstp));
341 E : EXPECT_NE(0, fstp.flags & FLAG_DST_WR);
342 :
343 E : _DInst fist = DecodeBuffer(kFist, sizeof(kFist));
344 E : EXPECT_NE(0, fist.flags & FLAG_DST_WR);
345 :
346 E : _DInst fistp = DecodeBuffer(kFistp, sizeof(kFistp));
347 E : EXPECT_NE(0, fistp.flags & FLAG_DST_WR);
348 E : }
349 :
350 : // If this test starts failing then Distorm now properly handles the vpermq
351 : // instruction. Please remove the workaround in disassembler_util.cc.
352 E : TEST(DisassemblerUtilTest, TestBadlyDecodedVpermq) {
353 : EXPECT_NO_FATAL_FAILURE(TestBadlyDecodedInstruction(
354 E : kVpermq, sizeof(kVpermq)));
355 E : }
356 :
357 : // If this test starts failing then Distorm now properly handles the vpermd
358 : // instruction. Please remove the workaround in disassembler_util.cc.
359 E : TEST(DisassemblerUtilTest, TestBadlyDecodedVpermd) {
360 : EXPECT_NO_FATAL_FAILURE(TestBadlyDecodedInstruction(
361 E : kVpermd, sizeof(kVpermd)));
362 E : }
363 :
364 : } // namespace core
|