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 : // Nop Instruction byte sequences.
75 : const uint8 kNop2Mov[] = { 0x8B, 0xFF };
76 : const uint8 kNop3Lea[] = { 0x8D, 0x49, 0x00 };
77 : const uint8 kNop1[] = { 0x90 };
78 : const uint8 kNop2[] = { 0x66, 0x90 };
79 : const uint8 kNop3[] = { 0x66, 0x66, 0x90 };
80 : const uint8 kNop4[] = { 0x0F, 0x1F, 0x40, 0x00 };
81 : const uint8 kNop5[] = { 0x0F, 0x1F, 0x44, 0x00, 0x00 };
82 : const uint8 kNop6[] = { 0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00 };
83 : const uint8 kNop7[] = { 0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00 };
84 : const uint8 kNop8[] = { 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
85 : const uint8 kNop9[] = {
86 : 0x66, // Prefix,
87 : 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 // kNop8.
88 : };
89 : const uint8 kNop10[] = {
90 : 0x66, 0x66, // Prefix.
91 : 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 // kNop8.
92 : };
93 : const uint8 kNop11[] = {
94 : 0x66, 0x66, 0x66, // Prefix.
95 : 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 // kNop8
96 : };
97 :
98 : // Call instruction.
99 : const uint8 kCall[] = { 0xE8, 0xCA, 0xFE, 0xBA, 0xBE };
100 :
101 : // Control Flow byte sequences (note that the JMP is indirect).
102 : const uint8 kJmp[] = { 0xFF, 0x24, 0x8D, 0xCA, 0xFE, 0xBA, 0xBE };
103 : const uint8 kRet[] = { 0xC3 };
104 : const uint8 kRetN[] = { 0xC2, 0x08, 0x00 };
105 : const uint8 kJe[] = { 0x74, 0xCA };
106 : const uint8 kSysEnter[] = { 0x0F, 0x34 };
107 : const uint8 kSysExit[] = { 0x0F, 0x35 };
108 :
109 : // Interrupts.
110 : const uint8 kInt2[] = { 0xCD, 0x02 };
111 : const uint8 kInt3[] = { 0xCC };
112 :
113 : } // namespace
114 :
115 E : TEST(DisassemblerUtilTest, DistormWrapperVxorpsPasses) {
116 E : _DInst inst = {};
117 E : EXPECT_TRUE(DecodeOneInstruction(kVxorps, sizeof(kVxorps), &inst));
118 E : }
119 :
120 E : TEST(DisassemblerUtilTest, InstructionToString) {
121 E : _DInst inst = {};
122 E : inst = DecodeBuffer(kNop1, sizeof(kNop1));
123 :
124 E : std::string Nop1Str;
125 E : EXPECT_TRUE(InstructionToString(inst, kNop1, sizeof(kNop1), &Nop1Str));
126 E : ASSERT_THAT(Nop1Str, testing::HasSubstr("90"));
127 E : ASSERT_THAT(Nop1Str, testing::HasSubstr("NOP"));
128 E : }
129 :
130 E : TEST(DisassemblerUtilTest, IsNop) {
131 E : EXPECT_FALSE(IsNop(DecodeBuffer(kJmp, sizeof(kJmp))));
132 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop1, sizeof(kNop1))));
133 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop2, sizeof(kNop2))));
134 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop3, sizeof(kNop3))));
135 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop4, sizeof(kNop4))));
136 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop5, sizeof(kNop5))));
137 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop6, sizeof(kNop6))));
138 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop7, sizeof(kNop7))));
139 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop8, sizeof(kNop8))));
140 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop9, sizeof(kNop9))));
141 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop10, sizeof(kNop10))));
142 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop11, sizeof(kNop11))));
143 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop2Mov, sizeof(kNop2Mov))));
144 E : EXPECT_TRUE(IsNop(DecodeBuffer(kNop3Lea, sizeof(kNop3Lea))));
145 E : }
146 :
147 E : TEST(DisassemblerUtilTest, IsCall) {
148 E : EXPECT_FALSE(IsCall(DecodeBuffer(kJmp, sizeof(kJmp))));
149 E : EXPECT_FALSE(IsCall(DecodeBuffer(kNop1, sizeof(kNop1))));
150 E : EXPECT_TRUE(IsCall(DecodeBuffer(kCall, sizeof(kCall))));
151 E : }
152 :
153 E : TEST(DisassemblerUtilTest, IsSystemCall) {
154 E : EXPECT_FALSE(IsSystemCall(DecodeBuffer(kJmp, sizeof(kJmp))));
155 E : EXPECT_FALSE(IsSystemCall(DecodeBuffer(kNop1, sizeof(kNop1))));
156 E : EXPECT_TRUE(IsSystemCall(DecodeBuffer(kSysEnter, sizeof(kSysEnter))));
157 E : EXPECT_TRUE(IsSystemCall(DecodeBuffer(kSysExit, sizeof(kSysExit))));
158 E : }
159 :
160 E : TEST(DisassemblerUtilTest, IsConditionalBranch) {
161 E : EXPECT_FALSE(IsConditionalBranch(DecodeBuffer(kNop4, sizeof(kNop4))));
162 E : EXPECT_FALSE(IsConditionalBranch(DecodeBuffer(kJmp, sizeof(kJmp))));
163 E : EXPECT_FALSE(IsConditionalBranch(DecodeBuffer(kRet, sizeof(kRet))));
164 E : EXPECT_TRUE(IsConditionalBranch(DecodeBuffer(kJe, sizeof(kJe))));
165 E : }
166 :
167 E : TEST(DisassemblerUtilTest, IsUnconditionalBranch) {
168 E : EXPECT_FALSE(IsUnconditionalBranch(DecodeBuffer(kNop4, sizeof(kNop4))));
169 E : EXPECT_FALSE(IsUnconditionalBranch(DecodeBuffer(kRet, sizeof(kRet))));
170 E : EXPECT_FALSE(IsUnconditionalBranch(DecodeBuffer(kJe, sizeof(kJe))));
171 E : EXPECT_TRUE(IsUnconditionalBranch(DecodeBuffer(kJmp, sizeof(kJmp))));
172 E : }
173 :
174 E : TEST(DisassemblerUtilTest, IsBranch) {
175 E : EXPECT_FALSE(IsBranch(DecodeBuffer(kNop4, sizeof(kNop4))));
176 E : EXPECT_FALSE(IsBranch(DecodeBuffer(kRet, sizeof(kRet))));
177 E : EXPECT_TRUE(IsBranch(DecodeBuffer(kJe, sizeof(kJe))));
178 E : EXPECT_TRUE(IsBranch(DecodeBuffer(kJmp, sizeof(kJmp))));
179 E : }
180 :
181 E : TEST(DisassemblerUtilTest, HasPcRelativeOperand) {
182 E : EXPECT_FALSE(HasPcRelativeOperand(DecodeBuffer(kRetN, sizeof(kRet)), 0));
183 E : EXPECT_FALSE(HasPcRelativeOperand(DecodeBuffer(kJmp, sizeof(kJmp)), 0));
184 E : EXPECT_TRUE(HasPcRelativeOperand(DecodeBuffer(kJe, sizeof(kJe)), 0));
185 E : }
186 :
187 E : TEST(DisassemblerUtilTest, IsControlFlow) {
188 E : EXPECT_FALSE(IsControlFlow(DecodeBuffer(kNop4, sizeof(kNop4))));
189 E : EXPECT_TRUE(IsControlFlow(DecodeBuffer(kJmp, sizeof(kJmp))));
190 E : EXPECT_TRUE(IsControlFlow(DecodeBuffer(kRet, sizeof(kRet))));
191 E : EXPECT_TRUE(IsControlFlow(DecodeBuffer(kRetN, sizeof(kRetN))));
192 E : EXPECT_TRUE(IsControlFlow(DecodeBuffer(kJe, sizeof(kJe))));
193 E : EXPECT_TRUE(IsControlFlow(DecodeBuffer(kSysEnter, sizeof(kSysEnter))));
194 E : }
195 :
196 E : TEST(DisassemblerUtilTest, IsImplicitControlFlow) {
197 E : EXPECT_FALSE(IsImplicitControlFlow(DecodeBuffer(kJe, sizeof(kJe))));
198 E : EXPECT_TRUE(IsImplicitControlFlow(DecodeBuffer(kRet, sizeof(kRet))));
199 E : EXPECT_TRUE(IsImplicitControlFlow(DecodeBuffer(kRetN, sizeof(kRetN))));
200 E : EXPECT_TRUE(IsImplicitControlFlow(DecodeBuffer(kJmp, sizeof(kJmp))));
201 E : }
202 :
203 E : TEST(DisassemblerUtilTest, IsInterrupt) {
204 E : EXPECT_FALSE(IsInterrupt(DecodeBuffer(kJe, sizeof(kJe))));
205 E : EXPECT_TRUE(IsInterrupt(DecodeBuffer(kInt2, sizeof(kInt2))));
206 E : EXPECT_TRUE(IsInterrupt(DecodeBuffer(kInt3, sizeof(kInt3))));
207 E : }
208 :
209 E : TEST(DisassemblerUtilTest, IsDebugInterrupt) {
210 E : EXPECT_FALSE(IsDebugInterrupt(DecodeBuffer(kJe, sizeof(kJe))));
211 E : EXPECT_FALSE(IsDebugInterrupt(DecodeBuffer(kInt2, sizeof(kInt2))));
212 E : EXPECT_TRUE(IsDebugInterrupt(DecodeBuffer(kInt3, sizeof(kInt3))));
213 E : }
214 :
215 E : TEST(DisassemblerUtilTest, DistormDecompose) {
216 E : const unsigned int kMaxResults = 16;
217 E : unsigned int result_count = 0;
218 : _DInst results[kMaxResults];
219 : EXPECT_EQ(DECRES_SUCCESS,
220 : DecomposeCode(kNop3Lea,
221 : sizeof(kNop3Lea),
222 : results,
223 : kMaxResults,
224 E : &result_count));
225 E : EXPECT_EQ(1U, result_count);
226 E : EXPECT_EQ(32U, results[0].ops[0].size);
227 E : }
228 :
229 E : TEST(DisassemblerUtilTest, DistormDecomposeFnstcw) {
230 E : const unsigned int kMaxResults = 16;
231 E : unsigned int result_count = 0;
232 : _DInst results[kMaxResults];
233 : EXPECT_EQ(DECRES_SUCCESS,
234 : DecomposeCode(kFnstcw,
235 : sizeof(kFnstcw),
236 : results,
237 : kMaxResults,
238 E : &result_count));
239 E : EXPECT_EQ(1U, result_count);
240 E : EXPECT_EQ(16U, results[0].ops[0].size);
241 E : }
242 :
243 E : TEST(DisassemblerUtilTest, WrongAccessSizeOnRawDistormDecomposeFnstcw) {
244 E : const unsigned int kMaxResults = 16;
245 E : unsigned int result_count = 0;
246 : _DInst results[kMaxResults];
247 : EXPECT_EQ(DECRES_SUCCESS,
248 : RawDecomposeCode(kFldcw,
249 : sizeof(kFldcw),
250 : results,
251 : kMaxResults,
252 E : &result_count));
253 E : EXPECT_EQ(1U, result_count);
254 E : EXPECT_EQ(0U, results[0].ops[0].size);
255 E : }
256 :
257 E : TEST(DisassemblerUtilTest, DistormDecomposeFldcw) {
258 E : const unsigned int kMaxResults = 16;
259 E : unsigned int result_count = 0;
260 : _DInst results[kMaxResults];
261 : EXPECT_EQ(DECRES_SUCCESS,
262 : DecomposeCode(kFldcw,
263 : sizeof(kFldcw),
264 : results,
265 : kMaxResults,
266 E : &result_count));
267 E : EXPECT_EQ(1U, result_count);
268 E : EXPECT_EQ(16U, results[0].ops[0].size);
269 E : }
270 :
271 E : TEST(DisassemblerUtilTest, WrongAccessSizeOnRawDistormDecomposeFldcw) {
272 E : const unsigned int kMaxResults = 16;
273 E : unsigned int result_count = 0;
274 : _DInst results[kMaxResults];
275 : EXPECT_EQ(DECRES_SUCCESS,
276 : RawDecomposeCode(kFldcw,
277 : sizeof(kFldcw),
278 : results,
279 : kMaxResults,
280 E : &result_count));
281 E : EXPECT_EQ(1U, result_count);
282 E : EXPECT_EQ(0U, results[0].ops[0].size);
283 E : }
284 :
285 : } // namespace core
|