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 : #include "syzygy/assm/unittest_util.h"
22 :
23 : namespace core {
24 :
25 : namespace {
26 :
27 : // Decompose a block of code using distorm wrapper.
28 : _DecodeResult DecomposeCode(const uint8* code_data,
29 : size_t length,
30 : _DInst result[],
31 : const unsigned int max_results,
32 E : unsigned int* result_count) {
33 E : _CodeInfo code = {};
34 E : code.dt = Decode32Bits;
35 E : code.features = DF_NONE;
36 E : code.codeOffset = 0;
37 E : code.codeLen = length;
38 E : code.code = code_data;
39 E : return DistormDecompose(&code, result, max_results, result_count);
40 E : }
41 :
42 : // Decompose a block of code using distorm directly.
43 : _DecodeResult RawDecomposeCode(const uint8* code_data,
44 : size_t length,
45 : _DInst result[],
46 : const unsigned int max_results,
47 E : unsigned int* result_count) {
48 E : _CodeInfo code = {};
49 E : code.dt = Decode32Bits;
50 E : code.features = DF_NONE;
51 E : code.codeOffset = 0;
52 E : code.codeLen = length;
53 E : code.code = code_data;
54 E : return distorm_decompose(&code, result, max_results, result_count);
55 E : }
56 :
57 E : _DInst DecodeBuffer(const uint8* buffer, size_t length) {
58 E : _DInst inst = {};
59 E : EXPECT_TRUE(DecodeOneInstruction(buffer, length, &inst));
60 E : EXPECT_EQ(length, inst.size);
61 E : return inst;
62 E : }
63 :
64 : // One of the AVX instructions that is currently not supported by distorm.
65 : // vxorps ymm0, ymm0, ymm0
66 : const uint8 kVxorps[] = { 0xC5, 0xFC, 0x57, 0xC0 };
67 :
68 : // Instructions for which distorm indicates a size of 0 for the destination
69 : // operand size.
70 : // fnstcw m16
71 : const uint8 kFnstcw[] = { 0xD9, 0x7D, 0xEA };
72 : // fldcw m16
73 : const uint8 kFldcw[] = { 0xD9, 0x6D, 0xE4 };
74 :
75 : // Instructions for which distorm do not activated the write flag.
76 : // fst qword ptr [0A374E8h]
77 : const uint8 kFst[] = { 0xDD, 0x15, 0xE8, 0x74, 0xA3, 0x00 };
78 : // fstp qword ptr [0A374E8h]
79 : const uint8 kFstp[] = { 0xDD, 0x1D, 0xE8, 0x74, 0xA3, 0x00 };
80 : // fist qword ptr [0A374E8h]
81 : const uint8 kFist[] = { 0xDB, 0x15, 0xE0, 0x74, 0xA3, 0x00 };
82 : // fistp qword ptr [0A374E8h]
83 : const uint8 kFistp[] = { 0xDB, 0x1D, 0xE0, 0x74, 0xA3, 0x00 };
84 :
85 : // Nop Instruction byte sequences.
86 : const uint8 kNop2Mov[] = { 0x8B, 0xFF };
87 : const uint8 kNop3Lea[] = { 0x8D, 0x49, 0x00 };
88 : // The recommended NOP sequences.
89 : using testing::kNop1;
90 : using testing::kNop2;
91 : using testing::kNop3;
92 : using testing::kNop4;
93 : using testing::kNop5;
94 : using testing::kNop6;
95 : using testing::kNop7;
96 : using testing::kNop8;
97 : using testing::kNop9;
98 : using testing::kNop10;
99 : using testing::kNop11;
100 :
101 : // Call instruction.
102 : const uint8 kCall[] = { 0xE8, 0xCA, 0xFE, 0xBA, 0xBE };
103 :
104 : // Control Flow byte sequences (note that the JMP is indirect).
105 : const uint8 kJmp[] = { 0xFF, 0x24, 0x8D, 0xCA, 0xFE, 0xBA, 0xBE };
106 : const uint8 kRet[] = { 0xC3 };
107 : const uint8 kRetN[] = { 0xC2, 0x08, 0x00 };
108 : const uint8 kJe[] = { 0x74, 0xCA };
109 : const uint8 kSysEnter[] = { 0x0F, 0x34 };
110 : const uint8 kSysExit[] = { 0x0F, 0x35 };
111 :
112 : // Interrupts.
113 : const uint8 kInt2[] = { 0xCD, 0x02 };
114 : const uint8 kInt3[] = { 0xCC };
115 :
116 : // Improperly handled 3-byte VEX encoded instructions.
117 : const uint8 kVpermq[] = { 0xC4, 0xE3, 0xFD, 0x00, 0xED, 0x44 };
118 : const uint8 kVpermd[] = { 0xC4, 0xE2, 0x4D, 0x36, 0xC0 };
119 : const uint8 kVbroadcasti128[] = { 0xC4, 0xE2, 0x7D, 0x5A, 0x45, 0xD0 };
120 : const uint8 kVinserti128[] = { 0xC4, 0xE3, 0x7D, 0x38, 0x2C, 0x0F, 0x01 };
121 : const uint8 kVpbroadcastb[] = { 0xC4, 0xE2, 0x79, 0x78, 0xC0 };
122 : const uint8 kVextracti128[] = { 0xC4, 0xE3, 0x7D, 0x39, 0xC8, 0x01};
123 :
124 E : void TestBadlyDecodedInstruction(const uint8* code, size_t code_length) {
125 E : _DInst inst[1] = {};
126 E : unsigned int inst_count = 0;
127 : _DecodeResult result = RawDecomposeCode(
128 E : code, code_length, inst, arraysize(inst), &inst_count);
129 E : EXPECT_EQ(DECRES_MEMORYERR, result);
130 E : EXPECT_EQ(0u, inst_count);
131 :
132 : result = DecomposeCode(
133 E : code, code_length, inst, arraysize(inst), &inst_count);
134 E : EXPECT_EQ(DECRES_SUCCESS, result);
135 E : EXPECT_EQ(1u, inst_count);
136 E : EXPECT_EQ(code_length, inst[0].size);
137 E : }
138 :
139 : } // namespace
140 :
141 E : TEST(DisassemblerUtilTest, DistormWrapperVxorpsPasses) {
142 E : _DInst inst = {};
143 E : EXPECT_TRUE(DecodeOneInstruction(kVxorps, sizeof(kVxorps), &inst));
144 E : }
145 :
146 E : TEST(DisassemblerUtilTest, InstructionToString) {
147 E : _DInst inst = {};
148 E : inst = DecodeBuffer(kNop1, sizeof(kNop1));
149 :
150 E : std::string Nop1Str;
151 E : EXPECT_TRUE(InstructionToString(inst, kNop1, sizeof(kNop1), &Nop1Str));
152 E : ASSERT_THAT(Nop1Str, testing::HasSubstr("90"));
153 E : ASSERT_THAT(Nop1Str, testing::HasSubstr("NOP"));
154 E : }
155 :
156 E : TEST(DisassemblerUtilTest, IsNop) {
157 E : EXPECT_FALSE(IsNop(DecodeBuffer(kJmp, sizeof(kJmp))));
158 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop1, sizeof(kNop1))));
159 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop2, sizeof(kNop2))));
160 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop3, sizeof(kNop3))));
161 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop4, sizeof(kNop4))));
162 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop5, sizeof(kNop5))));
163 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop6, sizeof(kNop6))));
164 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop7, sizeof(kNop7))));
165 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop8, sizeof(kNop8))));
166 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop9, sizeof(kNop9))));
167 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop10, sizeof(kNop10))));
168 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop11, sizeof(kNop11))));
169 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop2Mov, sizeof(kNop2Mov))));
170 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop3Lea, sizeof(kNop3Lea))));
171 E : }
172 :
173 E : TEST(DisassemblerUtilTest, IsCall) {
174 E : EXPECT_FALSE(IsCall(DecodeBuffer(kJmp, sizeof(kJmp))));
175 E : EXPECT_FALSE(IsCall(DecodeBuffer(kNop1, sizeof(kNop1))));
176 E : EXPECT_TRUE(IsCall(DecodeBuffer(kCall, sizeof(kCall))));
177 E : }
178 :
179 E : TEST(DisassemblerUtilTest, IsSystemCall) {
180 E : EXPECT_FALSE(IsSystemCall(DecodeBuffer(kJmp, sizeof(kJmp))));
181 E : EXPECT_FALSE(IsSystemCall(DecodeBuffer(kNop1, sizeof(kNop1))));
182 E : EXPECT_TRUE(IsSystemCall(DecodeBuffer(kSysEnter, sizeof(kSysEnter))));
183 E : EXPECT_TRUE(IsSystemCall(DecodeBuffer(kSysExit, sizeof(kSysExit))));
184 E : }
185 :
186 E : TEST(DisassemblerUtilTest, IsConditionalBranch) {
187 E : EXPECT_FALSE(IsConditionalBranch(DecodeBuffer(kNop4, sizeof(kNop4))));
188 E : EXPECT_FALSE(IsConditionalBranch(DecodeBuffer(kJmp, sizeof(kJmp))));
189 E : EXPECT_FALSE(IsConditionalBranch(DecodeBuffer(kRet, sizeof(kRet))));
190 E : EXPECT_TRUE(IsConditionalBranch(DecodeBuffer(kJe, sizeof(kJe))));
191 E : }
192 :
193 E : TEST(DisassemblerUtilTest, IsUnconditionalBranch) {
194 E : EXPECT_FALSE(IsUnconditionalBranch(DecodeBuffer(kNop4, sizeof(kNop4))));
195 E : EXPECT_FALSE(IsUnconditionalBranch(DecodeBuffer(kRet, sizeof(kRet))));
196 E : EXPECT_FALSE(IsUnconditionalBranch(DecodeBuffer(kJe, sizeof(kJe))));
197 E : EXPECT_TRUE(IsUnconditionalBranch(DecodeBuffer(kJmp, sizeof(kJmp))));
198 E : }
199 :
200 E : TEST(DisassemblerUtilTest, IsBranch) {
201 E : EXPECT_FALSE(IsBranch(DecodeBuffer(kNop4, sizeof(kNop4))));
202 E : EXPECT_FALSE(IsBranch(DecodeBuffer(kRet, sizeof(kRet))));
203 E : EXPECT_TRUE(IsBranch(DecodeBuffer(kJe, sizeof(kJe))));
204 E : EXPECT_TRUE(IsBranch(DecodeBuffer(kJmp, sizeof(kJmp))));
205 E : }
206 :
207 E : TEST(DisassemblerUtilTest, HasPcRelativeOperand) {
208 E : EXPECT_FALSE(HasPcRelativeOperand(DecodeBuffer(kRetN, sizeof(kRet)), 0));
209 E : EXPECT_FALSE(HasPcRelativeOperand(DecodeBuffer(kJmp, sizeof(kJmp)), 0));
210 E : EXPECT_TRUE(HasPcRelativeOperand(DecodeBuffer(kJe, sizeof(kJe)), 0));
211 E : }
212 :
213 E : TEST(DisassemblerUtilTest, IsControlFlow) {
214 E : EXPECT_FALSE(IsControlFlow(DecodeBuffer(kNop4, sizeof(kNop4))));
215 E : EXPECT_TRUE(IsControlFlow(DecodeBuffer(kJmp, sizeof(kJmp))));
216 E : EXPECT_TRUE(IsControlFlow(DecodeBuffer(kRet, sizeof(kRet))));
217 E : EXPECT_TRUE(IsControlFlow(DecodeBuffer(kRetN, sizeof(kRetN))));
218 E : EXPECT_TRUE(IsControlFlow(DecodeBuffer(kJe, sizeof(kJe))));
219 E : EXPECT_TRUE(IsControlFlow(DecodeBuffer(kSysEnter, sizeof(kSysEnter))));
220 E : }
221 :
222 E : TEST(DisassemblerUtilTest, IsImplicitControlFlow) {
223 E : EXPECT_FALSE(IsImplicitControlFlow(DecodeBuffer(kJe, sizeof(kJe))));
224 E : EXPECT_TRUE(IsImplicitControlFlow(DecodeBuffer(kRet, sizeof(kRet))));
225 E : EXPECT_TRUE(IsImplicitControlFlow(DecodeBuffer(kRetN, sizeof(kRetN))));
226 E : EXPECT_TRUE(IsImplicitControlFlow(DecodeBuffer(kJmp, sizeof(kJmp))));
227 E : }
228 :
229 E : TEST(DisassemblerUtilTest, IsInterrupt) {
230 E : EXPECT_FALSE(IsInterrupt(DecodeBuffer(kJe, sizeof(kJe))));
231 E : EXPECT_TRUE(IsInterrupt(DecodeBuffer(kInt2, sizeof(kInt2))));
232 E : EXPECT_TRUE(IsInterrupt(DecodeBuffer(kInt3, sizeof(kInt3))));
233 E : }
234 :
235 E : TEST(DisassemblerUtilTest, IsDebugInterrupt) {
236 E : EXPECT_FALSE(IsDebugInterrupt(DecodeBuffer(kJe, sizeof(kJe))));
237 E : EXPECT_FALSE(IsDebugInterrupt(DecodeBuffer(kInt2, sizeof(kInt2))));
238 E : EXPECT_TRUE(IsDebugInterrupt(DecodeBuffer(kInt3, sizeof(kInt3))));
239 E : }
240 :
241 E : TEST(DisassemblerUtilTest, GetRegisterType) {
242 E : EXPECT_EQ(R_DL, GetRegisterType(assm::kRegisterDl));
243 E : EXPECT_EQ(R_AX, GetRegisterType(assm::kRegisterAx));
244 E : EXPECT_EQ(R_EDI, GetRegisterType(assm::kRegisterEdi));
245 :
246 E : EXPECT_EQ(R_BH, GetRegisterType(assm::bh));
247 E : EXPECT_EQ(R_CX, GetRegisterType(assm::cx));
248 E : EXPECT_EQ(R_ESP, GetRegisterType(assm::esp));
249 E : }
250 :
251 E : TEST(DisassemblerUtilTest, GetRegisterId) {
252 E : EXPECT_EQ(assm::kRegisterAl, GetRegisterId(R_AL));
253 E : EXPECT_EQ(assm::kRegisterSp, GetRegisterId(R_SP));
254 E : EXPECT_EQ(assm::kRegisterEdi, GetRegisterId(R_EDI));
255 E : }
256 :
257 E : TEST(DisassemblerUtilTest, GetRegister) {
258 E : EXPECT_EQ(assm::bh, GetRegister(R_BH));
259 E : EXPECT_EQ(assm::cx, GetRegister(R_CX));
260 E : EXPECT_EQ(assm::ebp, GetRegister(R_EBP));
261 E : }
262 :
263 E : TEST(DisassemblerUtilTest, DistormDecompose) {
264 E : const unsigned int kMaxResults = 16;
265 E : unsigned int result_count = 0;
266 : _DInst results[kMaxResults];
267 : EXPECT_EQ(DECRES_SUCCESS,
268 : DecomposeCode(kNop3Lea,
269 : sizeof(kNop3Lea),
270 : results,
271 : kMaxResults,
272 E : &result_count));
273 E : EXPECT_EQ(1U, result_count);
274 E : EXPECT_EQ(32U, results[0].ops[0].size);
275 E : }
276 :
277 E : TEST(DisassemblerUtilTest, DistormDecomposeFnstcw) {
278 E : const unsigned int kMaxResults = 16;
279 E : unsigned int result_count = 0;
280 : _DInst results[kMaxResults];
281 : EXPECT_EQ(DECRES_SUCCESS,
282 : DecomposeCode(kFnstcw,
283 : sizeof(kFnstcw),
284 : results,
285 : kMaxResults,
286 E : &result_count));
287 E : EXPECT_EQ(1U, result_count);
288 E : EXPECT_EQ(16U, results[0].ops[0].size);
289 E : }
290 :
291 E : TEST(DisassemblerUtilTest, DistormDecomposeFldcw) {
292 E : const unsigned int kMaxResults = 16;
293 E : unsigned int result_count = 0;
294 : _DInst results[kMaxResults];
295 : EXPECT_EQ(DECRES_SUCCESS,
296 : DecomposeCode(kFldcw,
297 : sizeof(kFldcw),
298 : results,
299 : kMaxResults,
300 E : &result_count));
301 E : EXPECT_EQ(1U, result_count);
302 E : EXPECT_EQ(16U, results[0].ops[0].size);
303 E : }
304 :
305 : // If one of these test starts failing then Distorm now properly handles the
306 : // AVX2 instructions. Please remove the workaround in disassembler_util.cc.
307 :
308 E : TEST(DisassemblerUtilTest, TestBadlyDecodedVpermq) {
309 : EXPECT_NO_FATAL_FAILURE(TestBadlyDecodedInstruction(
310 E : kVpermq, sizeof(kVpermq)));
311 E : }
312 :
313 E : TEST(DisassemblerUtilTest, TestBadlyDecodedVpermd) {
314 : EXPECT_NO_FATAL_FAILURE(TestBadlyDecodedInstruction(
315 E : kVpermd, sizeof(kVpermd)));
316 E : }
317 :
318 E : TEST(DisassemblerUtilTest, TestBadlyDecodedVbroadcasti128) {
319 : EXPECT_NO_FATAL_FAILURE(TestBadlyDecodedInstruction(
320 E : kVbroadcasti128, sizeof(kVbroadcasti128)));
321 E : }
322 :
323 E : TEST(DisassemblerUtilTest, TestBadlyDecodedVinserti128) {
324 : EXPECT_NO_FATAL_FAILURE(TestBadlyDecodedInstruction(
325 E : kVinserti128, sizeof(kVinserti128)));
326 E : }
327 :
328 E : TEST(DisassemblerUtilTest, TestBadlyDecodedVpbroadcastb) {
329 : EXPECT_NO_FATAL_FAILURE(TestBadlyDecodedInstruction(
330 E : kVpbroadcastb, sizeof(kVpbroadcastb)));
331 E : }
332 :
333 E : TEST(DisassemblerUtilTest, TestBadlyDecodedVextracti128) {
334 : EXPECT_NO_FATAL_FAILURE(TestBadlyDecodedInstruction(
335 E : kVextracti128, sizeof(kVextracti128)));
336 E : }
337 :
338 : } // namespace core
|