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/logging.h"
18 : #include "gmock/gmock.h"
19 : #include "gtest/gtest.h"
20 : #include "syzygy/assm/unittest_util.h"
21 :
22 : namespace core {
23 :
24 : namespace {
25 :
26 : // Decompose a block of code using distorm wrapper.
27 : _DecodeResult DecomposeCode(const uint8_t* 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_t* 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_t* 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_t kVxorps[] = {0xC5, 0xFC, 0x57, 0xC0};
66 :
67 : // Instructions for which distorm indicates a size of 0 for the destination
68 : // operand size.
69 : const uint8_t kFxsave[] = {0x0F, 0xAE, 0x00};
70 : const uint8_t kFxrstor[] = {0x0F, 0xAE, 0x08};
71 :
72 : // FPU instructions for which distorm had some decoding issues in the past.
73 : // fnstcw m16
74 : const uint8_t kFnstcw[] = {0xD9, 0x7D, 0xEA};
75 : // fldcw m16
76 : const uint8_t kFldcw[] = {0xD9, 0x6D, 0xE4};
77 :
78 : // Instructions for which distorm do not activated the write flag.
79 : // fst qword ptr [0A374E8h]
80 : const uint8_t kFst[] = {0xDD, 0x15, 0xE8, 0x74, 0xA3, 0x00};
81 : // fstp qword ptr [0A374E8h]
82 : const uint8_t kFstp[] = {0xDD, 0x1D, 0xE8, 0x74, 0xA3, 0x00};
83 : // fist qword ptr [0A374E8h]
84 : const uint8_t kFist[] = {0xDB, 0x15, 0xE0, 0x74, 0xA3, 0x00};
85 : // fistp qword ptr [0A374E8h]
86 : const uint8_t kFistp[] = {0xDB, 0x1D, 0xE0, 0x74, 0xA3, 0x00};
87 :
88 : // Nop Instruction byte sequences.
89 : const uint8_t kNop2Mov[] = {0x8B, 0xFF};
90 : const uint8_t kNop3Lea[] = {0x8D, 0x49, 0x00};
91 : // The recommended NOP sequences.
92 : using testing::kNop1;
93 : using testing::kNop2;
94 : using testing::kNop3;
95 : using testing::kNop4;
96 : using testing::kNop5;
97 : using testing::kNop6;
98 : using testing::kNop7;
99 : using testing::kNop8;
100 : using testing::kNop9;
101 : using testing::kNop10;
102 : using testing::kNop11;
103 :
104 : // Call instruction.
105 : const uint8_t kCall[] = {0xE8, 0xCA, 0xFE, 0xBA, 0xBE};
106 :
107 : // Control Flow byte sequences (note that the JMP is indirect).
108 : const uint8_t kJmp[] = {0xFF, 0x24, 0x8D, 0xCA, 0xFE, 0xBA, 0xBE};
109 : const uint8_t kRet[] = {0xC3};
110 : const uint8_t kRetN[] = {0xC2, 0x08, 0x00};
111 : const uint8_t kJe[] = {0x74, 0xCA};
112 : const uint8_t kSysEnter[] = {0x0F, 0x34};
113 : const uint8_t kSysExit[] = {0x0F, 0x35};
114 :
115 : // Interrupts.
116 : const uint8_t kInt2[] = {0xCD, 0x02};
117 : const uint8_t kInt3[] = {0xCC};
118 :
119 : // Improperly handled VEX encoded instructions.
120 : const uint8_t kVpermq[] = {0xC4, 0xE3, 0xFD, 0x00, 0xED, 0x44};
121 : const uint8_t kVpermd[] = {0xC4, 0xE2, 0x4D, 0x36, 0xC0};
122 : const uint8_t kVbroadcasti128[] = {0xC4, 0xE2, 0x7D, 0x5A, 0x45, 0xD0};
123 : const uint8_t kVinserti128[] = {0xC4, 0xE3, 0x7D, 0x38, 0x2C, 0x0F, 0x01};
124 : const uint8_t kVpbroadcastb[] = {0xC4, 0xE2, 0x79, 0x78, 0xC0};
125 : const uint8_t kVextracti128[] = {0xC4, 0xE3, 0x7D, 0x39, 0xC8, 0x01};
126 : const uint8_t kVcvtps2ph[] = {0xC4, 0xE3, 0x79, 0x1D, 0xC8, 0x00};
127 : const uint8_t kVcvtps2ps[] = {0xC4, 0xE2, 0x79, 0x13, 0xE0};
128 :
129 E : void TestBadlyDecodedInstruction(const uint8_t* code, size_t code_length) {
130 E : _DInst inst[1] = {};
131 E : unsigned int inst_count = 0;
132 E : _DecodeResult result = RawDecomposeCode(
133 : code, code_length, inst, arraysize(inst), &inst_count);
134 E : EXPECT_EQ(DECRES_MEMORYERR, result);
135 E : EXPECT_EQ(0u, inst_count);
136 :
137 E : result = DecomposeCode(
138 : code, code_length, inst, arraysize(inst), &inst_count);
139 E : EXPECT_EQ(DECRES_SUCCESS, result);
140 E : EXPECT_EQ(1u, inst_count);
141 E : EXPECT_EQ(code_length, inst[0].size);
142 E : }
143 :
144 : } // namespace
145 :
146 E : TEST(DisassemblerUtilTest, DistormWrapperVxorpsPasses) {
147 E : _DInst inst = {};
148 E : EXPECT_TRUE(DecodeOneInstruction(kVxorps, sizeof(kVxorps), &inst));
149 E : }
150 :
151 E : TEST(DisassemblerUtilTest, InstructionToString) {
152 E : _DInst inst = {};
153 E : inst = DecodeBuffer(kNop1, sizeof(kNop1));
154 :
155 E : std::string Nop1Str;
156 E : EXPECT_TRUE(InstructionToString(inst, kNop1, sizeof(kNop1), &Nop1Str));
157 E : ASSERT_THAT(Nop1Str, testing::HasSubstr("90"));
158 E : ASSERT_THAT(Nop1Str, testing::HasSubstr("NOP"));
159 E : }
160 :
161 E : TEST(DisassemblerUtilTest, IsNop) {
162 E : EXPECT_FALSE(IsNop(DecodeBuffer(kJmp, sizeof(kJmp))));
163 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop1, sizeof(kNop1))));
164 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop2, sizeof(kNop2))));
165 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop3, sizeof(kNop3))));
166 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop4, sizeof(kNop4))));
167 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop5, sizeof(kNop5))));
168 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop6, sizeof(kNop6))));
169 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop7, sizeof(kNop7))));
170 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop8, sizeof(kNop8))));
171 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop9, sizeof(kNop9))));
172 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop10, sizeof(kNop10))));
173 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop11, sizeof(kNop11))));
174 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop2Mov, sizeof(kNop2Mov))));
175 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop3Lea, sizeof(kNop3Lea))));
176 E : }
177 :
178 E : TEST(DisassemblerUtilTest, IsCall) {
179 E : EXPECT_FALSE(IsCall(DecodeBuffer(kJmp, sizeof(kJmp))));
180 E : EXPECT_FALSE(IsCall(DecodeBuffer(kNop1, sizeof(kNop1))));
181 E : EXPECT_TRUE(IsCall(DecodeBuffer(kCall, sizeof(kCall))));
182 E : }
183 :
184 E : TEST(DisassemblerUtilTest, IsSystemCall) {
185 E : EXPECT_FALSE(IsSystemCall(DecodeBuffer(kJmp, sizeof(kJmp))));
186 E : EXPECT_FALSE(IsSystemCall(DecodeBuffer(kNop1, sizeof(kNop1))));
187 E : EXPECT_TRUE(IsSystemCall(DecodeBuffer(kSysEnter, sizeof(kSysEnter))));
188 E : EXPECT_TRUE(IsSystemCall(DecodeBuffer(kSysExit, sizeof(kSysExit))));
189 E : }
190 :
191 E : TEST(DisassemblerUtilTest, IsConditionalBranch) {
192 E : EXPECT_FALSE(IsConditionalBranch(DecodeBuffer(kNop4, sizeof(kNop4))));
193 E : EXPECT_FALSE(IsConditionalBranch(DecodeBuffer(kJmp, sizeof(kJmp))));
194 E : EXPECT_FALSE(IsConditionalBranch(DecodeBuffer(kRet, sizeof(kRet))));
195 E : EXPECT_TRUE(IsConditionalBranch(DecodeBuffer(kJe, sizeof(kJe))));
196 E : }
197 :
198 E : TEST(DisassemblerUtilTest, IsUnconditionalBranch) {
199 E : EXPECT_FALSE(IsUnconditionalBranch(DecodeBuffer(kNop4, sizeof(kNop4))));
200 E : EXPECT_FALSE(IsUnconditionalBranch(DecodeBuffer(kRet, sizeof(kRet))));
201 E : EXPECT_FALSE(IsUnconditionalBranch(DecodeBuffer(kJe, sizeof(kJe))));
202 E : EXPECT_TRUE(IsUnconditionalBranch(DecodeBuffer(kJmp, sizeof(kJmp))));
203 E : }
204 :
205 E : TEST(DisassemblerUtilTest, IsBranch) {
206 E : EXPECT_FALSE(IsBranch(DecodeBuffer(kNop4, sizeof(kNop4))));
207 E : EXPECT_FALSE(IsBranch(DecodeBuffer(kRet, sizeof(kRet))));
208 E : EXPECT_TRUE(IsBranch(DecodeBuffer(kJe, sizeof(kJe))));
209 E : EXPECT_TRUE(IsBranch(DecodeBuffer(kJmp, sizeof(kJmp))));
210 E : }
211 :
212 E : TEST(DisassemblerUtilTest, HasPcRelativeOperand) {
213 E : EXPECT_FALSE(HasPcRelativeOperand(DecodeBuffer(kRetN, sizeof(kRet)), 0));
214 E : EXPECT_FALSE(HasPcRelativeOperand(DecodeBuffer(kJmp, sizeof(kJmp)), 0));
215 E : EXPECT_TRUE(HasPcRelativeOperand(DecodeBuffer(kJe, sizeof(kJe)), 0));
216 E : }
217 :
218 E : TEST(DisassemblerUtilTest, IsControlFlow) {
219 E : EXPECT_FALSE(IsControlFlow(DecodeBuffer(kNop4, sizeof(kNop4))));
220 E : EXPECT_TRUE(IsControlFlow(DecodeBuffer(kJmp, sizeof(kJmp))));
221 E : EXPECT_TRUE(IsControlFlow(DecodeBuffer(kRet, sizeof(kRet))));
222 E : EXPECT_TRUE(IsControlFlow(DecodeBuffer(kRetN, sizeof(kRetN))));
223 E : EXPECT_TRUE(IsControlFlow(DecodeBuffer(kJe, sizeof(kJe))));
224 E : EXPECT_TRUE(IsControlFlow(DecodeBuffer(kSysEnter, sizeof(kSysEnter))));
225 E : }
226 :
227 E : TEST(DisassemblerUtilTest, IsImplicitControlFlow) {
228 E : EXPECT_FALSE(IsImplicitControlFlow(DecodeBuffer(kJe, sizeof(kJe))));
229 E : EXPECT_TRUE(IsImplicitControlFlow(DecodeBuffer(kRet, sizeof(kRet))));
230 E : EXPECT_TRUE(IsImplicitControlFlow(DecodeBuffer(kRetN, sizeof(kRetN))));
231 E : EXPECT_TRUE(IsImplicitControlFlow(DecodeBuffer(kJmp, sizeof(kJmp))));
232 E : }
233 :
234 E : TEST(DisassemblerUtilTest, IsInterrupt) {
235 E : EXPECT_FALSE(IsInterrupt(DecodeBuffer(kJe, sizeof(kJe))));
236 E : EXPECT_TRUE(IsInterrupt(DecodeBuffer(kInt2, sizeof(kInt2))));
237 E : EXPECT_TRUE(IsInterrupt(DecodeBuffer(kInt3, sizeof(kInt3))));
238 E : }
239 :
240 E : TEST(DisassemblerUtilTest, IsDebugInterrupt) {
241 E : EXPECT_FALSE(IsDebugInterrupt(DecodeBuffer(kJe, sizeof(kJe))));
242 E : EXPECT_FALSE(IsDebugInterrupt(DecodeBuffer(kInt2, sizeof(kInt2))));
243 E : EXPECT_TRUE(IsDebugInterrupt(DecodeBuffer(kInt3, sizeof(kInt3))));
244 E : }
245 :
246 E : TEST(DisassemblerUtilTest, GetRegisterType) {
247 E : EXPECT_EQ(R_DL, GetRegisterType(assm::kRegisterDl));
248 E : EXPECT_EQ(R_AX, GetRegisterType(assm::kRegisterAx));
249 E : EXPECT_EQ(R_EDI, GetRegisterType(assm::kRegisterEdi));
250 :
251 E : EXPECT_EQ(R_BH, GetRegisterType(assm::bh));
252 E : EXPECT_EQ(R_CX, GetRegisterType(assm::cx));
253 E : EXPECT_EQ(R_ESP, GetRegisterType(assm::esp));
254 E : }
255 :
256 E : TEST(DisassemblerUtilTest, GetRegisterId) {
257 E : EXPECT_EQ(assm::kRegisterAl, GetRegisterId(R_AL));
258 E : EXPECT_EQ(assm::kRegisterSp, GetRegisterId(R_SP));
259 E : EXPECT_EQ(assm::kRegisterEdi, GetRegisterId(R_EDI));
260 E : }
261 :
262 E : TEST(DisassemblerUtilTest, GetRegister) {
263 E : EXPECT_EQ(assm::bh, GetRegister(R_BH));
264 E : EXPECT_EQ(assm::cx, GetRegister(R_CX));
265 E : EXPECT_EQ(assm::ebp, GetRegister(R_EBP));
266 E : }
267 :
268 E : TEST(DisassemblerUtilTest, DistormDecompose) {
269 E : const unsigned int kMaxResults = 16;
270 E : unsigned int result_count = 0;
271 : _DInst results[kMaxResults];
272 E : EXPECT_EQ(DECRES_SUCCESS,
273 : DecomposeCode(kNop3Lea,
274 : sizeof(kNop3Lea),
275 : results,
276 : kMaxResults,
277 E : &result_count));
278 E : EXPECT_EQ(1U, result_count);
279 E : EXPECT_EQ(32U, results[0].ops[0].size);
280 E : }
281 :
282 E : TEST(DisassemblerUtilTest, DistormDecomposeFnstcw) {
283 E : const unsigned int kMaxResults = 16;
284 E : unsigned int result_count = 0;
285 : _DInst results[kMaxResults];
286 E : EXPECT_EQ(DECRES_SUCCESS,
287 : DecomposeCode(kFnstcw,
288 : sizeof(kFnstcw),
289 : results,
290 : kMaxResults,
291 E : &result_count));
292 E : EXPECT_EQ(1U, result_count);
293 E : EXPECT_EQ(16U, results[0].ops[0].size);
294 E : }
295 :
296 E : TEST(DisassemblerUtilTest, DistormDecomposeFldcw) {
297 E : const unsigned int kMaxResults = 16;
298 E : unsigned int result_count = 0;
299 : _DInst results[kMaxResults];
300 E : EXPECT_EQ(DECRES_SUCCESS,
301 : DecomposeCode(kFldcw,
302 : sizeof(kFldcw),
303 : results,
304 : kMaxResults,
305 E : &result_count));
306 E : EXPECT_EQ(1U, result_count);
307 E : EXPECT_EQ(16U, results[0].ops[0].size);
308 E : }
309 :
310 E : TEST(DisassemblerUtilTest, WrongAccessSizeOnRawDistormDecomposeFxsave) {
311 E : const unsigned int kMaxResults = 16;
312 E : unsigned int result_count = 0;
313 : _DInst results[kMaxResults];
314 E : EXPECT_EQ(DECRES_SUCCESS, RawDecomposeCode(kFxsave, sizeof(kFxsave), results,
315 E : kMaxResults, &result_count));
316 E : EXPECT_EQ(1U, result_count);
317 E : EXPECT_EQ(0U, results[0].ops[0].size);
318 E : }
319 :
320 E : TEST(DisassemblerUtilTest, DistormDecomposeFxsave) {
321 E : const unsigned int kMaxResults = 16;
322 E : unsigned int result_count = 0;
323 : _DInst results[kMaxResults];
324 E : EXPECT_EQ(DECRES_SUCCESS,
325 : DecomposeCode(kFxsave,
326 : sizeof(kFxsave),
327 : results,
328 : kMaxResults,
329 E : &result_count));
330 E : EXPECT_EQ(1, result_count);
331 E : EXPECT_EQ(64, results[0].ops[0].size);
332 E : }
333 :
334 E : TEST(DisassemblerUtilTest, WrongAccessSizeOnRawDistormDecomposeFxrstor) {
335 E : const unsigned int kMaxResults = 16;
336 E : unsigned int result_count = 0;
337 : _DInst results[kMaxResults];
338 E : EXPECT_EQ(DECRES_SUCCESS,
339 : RawDecomposeCode(kFxrstor, sizeof(kFxrstor), results, kMaxResults,
340 E : &result_count));
341 E : EXPECT_EQ(1U, result_count);
342 E : EXPECT_EQ(0U, results[0].ops[0].size);
343 E : }
344 :
345 E : TEST(DisassemblerUtilTest, DistormDecomposeFxrstor) {
346 E : const unsigned int kMaxResults = 16;
347 E : unsigned int result_count = 0;
348 : _DInst results[kMaxResults];
349 E : EXPECT_EQ(DECRES_SUCCESS,
350 : DecomposeCode(kFxrstor,
351 : sizeof(kFxrstor),
352 : results,
353 : kMaxResults,
354 E : &result_count));
355 E : EXPECT_EQ(1, result_count);
356 E : EXPECT_EQ(64, results[0].ops[0].size);
357 E : }
358 :
359 : // If one of these test starts failing then Distorm now properly handles the
360 : // AVX2 instructions. Please remove the workaround in disassembler_util.cc.
361 :
362 E : TEST(DisassemblerUtilTest, TestBadlyDecodedVpermq) {
363 E : EXPECT_NO_FATAL_FAILURE(TestBadlyDecodedInstruction(
364 E : kVpermq, sizeof(kVpermq)));
365 E : }
366 :
367 E : TEST(DisassemblerUtilTest, TestBadlyDecodedVpermd) {
368 E : EXPECT_NO_FATAL_FAILURE(TestBadlyDecodedInstruction(
369 E : kVpermd, sizeof(kVpermd)));
370 E : }
371 :
372 E : TEST(DisassemblerUtilTest, TestBadlyDecodedVbroadcasti128) {
373 E : EXPECT_NO_FATAL_FAILURE(TestBadlyDecodedInstruction(
374 E : kVbroadcasti128, sizeof(kVbroadcasti128)));
375 E : }
376 :
377 E : TEST(DisassemblerUtilTest, TestBadlyDecodedVinserti128) {
378 E : EXPECT_NO_FATAL_FAILURE(TestBadlyDecodedInstruction(
379 E : kVinserti128, sizeof(kVinserti128)));
380 E : }
381 :
382 E : TEST(DisassemblerUtilTest, TestBadlyDecodedVpbroadcastb) {
383 E : EXPECT_NO_FATAL_FAILURE(TestBadlyDecodedInstruction(
384 E : kVpbroadcastb, sizeof(kVpbroadcastb)));
385 E : }
386 :
387 E : TEST(DisassemblerUtilTest, TestBadlyDecodedVextracti128) {
388 E : EXPECT_NO_FATAL_FAILURE(TestBadlyDecodedInstruction(
389 E : kVextracti128, sizeof(kVextracti128)));
390 E : }
391 :
392 E : TEST(DisassemblerUtilTest, TestBadlyDecodedVcvtps2ph) {
393 E : EXPECT_NO_FATAL_FAILURE(TestBadlyDecodedInstruction(
394 E : kVcvtps2ph, sizeof(kVcvtps2ph)));
395 E : }
396 :
397 E : TEST(DisassemblerUtilTest, TestBadlyDecodedVcvtps2ps) {
398 E : EXPECT_NO_FATAL_FAILURE(TestBadlyDecodedInstruction(
399 E : kVcvtps2ps, sizeof(kVcvtps2ps)));
400 E : }
401 :
402 : } // namespace core
|