ZydisTestEncoderAbsolute.c
1 /*************************************************************************************************** 2 3 Zyan Disassembler Library (Zydis) 4 5 Original Author : Mappa 6 7 * Permission is hereby granted, free of charge, to any person obtaining a copy 8 * of this software and associated documentation files (the "Software"), to deal 9 * in the Software without restriction, including without limitation the rights 10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 * copies of the Software, and to permit persons to whom the Software is 12 * furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included in all 15 * copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. 24 25 ***************************************************************************************************/ 26 27 /** 28 * @file 29 * 30 * Test set for `ZydisEncoderEncodeInstructionAbsolute`. 31 */ 32 33 #include <inttypes.h> 34 #include <Zycore/LibC.h> 35 #include <Zydis/Zydis.h> 36 #include <Zydis/Internal/EncoderData.h> 37 38 /* ============================================================================================== */ 39 /* Enums and Types */ 40 /* ============================================================================================== */ 41 42 #define TEST_RUNTIME_ADDRESS 0x00004000 43 44 typedef struct Iterator_ 45 { 46 ZyanU32 value; 47 ZyanU32 limit; 48 } Iterator; 49 50 /* ============================================================================================== */ 51 /* Helper functions */ 52 /* ============================================================================================== */ 53 54 static ZyanBool AdvanceIterators(Iterator *iterators, ZyanUSize count) 55 { 56 if (!iterators || !count) 57 { 58 return ZYAN_FALSE; 59 } 60 61 for (ZyanUSize i = 0; i < count; ++i) 62 { 63 Iterator *iterator = &iterators[count - 1 - i]; 64 iterator->value++; 65 if (iterator->value < iterator->limit) 66 { 67 return ZYAN_TRUE; 68 } 69 iterator->value = 0; 70 } 71 72 return ZYAN_FALSE; 73 } 74 75 static void PrintBytes(ZyanU8 *bytes, ZyanUSize count) 76 { 77 for (ZyanUSize i = 0; i < count; ++i) 78 { 79 ZYAN_PRINTF("%02X ", bytes[i]); 80 } 81 } 82 83 /* ============================================================================================== */ 84 /* Tests */ 85 /* ============================================================================================== */ 86 87 static ZyanBool RunTest(ZydisEncoderRequest *req, const char *test_name, ZyanU8 rel_op_index, 88 ZyanBool is_rip_rel_test) 89 { 90 ZyanU8 instruction1[ZYDIS_MAX_INSTRUCTION_LENGTH]; 91 ZyanUSize length1 = sizeof(instruction1); 92 if (ZYAN_FAILED(ZydisEncoderEncodeInstruction(req, instruction1, &length1))) 93 { 94 ZYAN_PRINTF("%s: NOT ENCODABLE\n", test_name); 95 return ZYAN_TRUE; 96 } 97 98 ZydisDecoder decoder; 99 ZydisStackWidth stack_width; 100 ZydisDecodedInstruction dec_instruction; 101 ZydisDecodedOperand dec_operands[ZYDIS_MAX_OPERAND_COUNT]; 102 switch (req->machine_mode) 103 { 104 case ZYDIS_MACHINE_MODE_LONG_COMPAT_16: 105 stack_width = ZYDIS_STACK_WIDTH_16; 106 break; 107 case ZYDIS_MACHINE_MODE_LONG_COMPAT_32: 108 stack_width = ZYDIS_STACK_WIDTH_32; 109 break; 110 case ZYDIS_MACHINE_MODE_LONG_64: 111 stack_width = ZYDIS_STACK_WIDTH_64; 112 break; 113 default: 114 ZYAN_UNREACHABLE; 115 } 116 if (ZYAN_FAILED(ZydisDecoderInit(&decoder, req->machine_mode, stack_width))) 117 { 118 ZYAN_PRINTF("%s: FAILED TO INITIALIZE DECODER\n", test_name); 119 return ZYAN_FALSE; 120 } 121 if (ZYAN_FAILED(ZydisDecoderDecodeFull(&decoder, instruction1, sizeof(instruction1), 122 &dec_instruction, dec_operands))) 123 { 124 ZYAN_PRINTF("%s: FAILED TO DECODE INSTRUCTION\n", test_name); 125 return ZYAN_FALSE; 126 } 127 ZyanU64 absolute_address = 0; 128 if (ZYAN_FAILED(ZydisCalcAbsoluteAddress(&dec_instruction, &dec_operands[rel_op_index], 129 TEST_RUNTIME_ADDRESS, &absolute_address))) 130 { 131 ZYAN_PRINTF("%s: FAILED TO COMPUTE ABSOLUTE ADDRESS\n", test_name); 132 return ZYAN_FALSE; 133 } 134 if (is_rip_rel_test) 135 { 136 ZYAN_ASSERT(req->operands[rel_op_index].type == ZYDIS_OPERAND_TYPE_MEMORY); 137 req->operands[rel_op_index].mem.displacement = absolute_address; 138 } 139 else 140 { 141 ZYAN_ASSERT(req->operands[rel_op_index].type == ZYDIS_OPERAND_TYPE_IMMEDIATE); 142 req->operands[rel_op_index].imm.u = absolute_address; 143 } 144 145 ZyanU8 instruction2[ZYDIS_MAX_INSTRUCTION_LENGTH]; 146 ZyanUSize length2 = sizeof(instruction2); 147 if (ZYAN_FAILED(ZydisEncoderEncodeInstructionAbsolute(req, instruction2, &length2, 148 TEST_RUNTIME_ADDRESS))) 149 { 150 ZYAN_PRINTF("%s: FAILED TO ENCODE INSTRUCTION\n", test_name); 151 return ZYAN_FALSE; 152 } 153 ZYAN_PRINTF("%s: ", test_name); 154 PrintBytes(instruction1, length1); 155 if ((length1 != length2) || ZYAN_MEMCMP(instruction1, instruction2, length1)) 156 { 157 ZYAN_PRINTF("!= "); 158 PrintBytes(instruction2, length2); 159 ZYAN_PRINTF("\n"); 160 return ZYAN_FALSE; 161 } 162 ZYAN_PRINTF("\n"); 163 return ZYAN_TRUE; 164 } 165 166 static ZyanBool RunBranchingTests() 167 { 168 static const ZydisMnemonic instructions[] = 169 { 170 ZYDIS_MNEMONIC_CALL, 171 ZYDIS_MNEMONIC_JZ, 172 ZYDIS_MNEMONIC_JCXZ, 173 ZYDIS_MNEMONIC_JECXZ, 174 ZYDIS_MNEMONIC_JRCXZ, 175 ZYDIS_MNEMONIC_JKZD, 176 ZYDIS_MNEMONIC_JMP, 177 }; 178 static const ZydisMachineMode modes[] = 179 { 180 ZYDIS_MACHINE_MODE_LONG_COMPAT_16, 181 ZYDIS_MACHINE_MODE_LONG_COMPAT_32, 182 ZYDIS_MACHINE_MODE_LONG_64, 183 }; 184 static const char *str_modes[] = 185 { 186 "M16", 187 "M32", 188 "M64", 189 }; 190 static const ZyanU64 rels[] = 191 { 192 0x11, 193 0x2222, 194 0x44444444, 195 }; 196 static const ZydisBranchType branch_types[] = 197 { 198 ZYDIS_BRANCH_TYPE_NONE, 199 ZYDIS_BRANCH_TYPE_SHORT, 200 ZYDIS_BRANCH_TYPE_NEAR, 201 }; 202 static const char *str_branch_types[] = 203 { 204 "T0", 205 "TS", 206 "TN", 207 }; 208 static const ZydisBranchWidth branch_widths[] = 209 { 210 ZYDIS_BRANCH_WIDTH_NONE, 211 ZYDIS_BRANCH_WIDTH_8, 212 ZYDIS_BRANCH_WIDTH_16, 213 ZYDIS_BRANCH_WIDTH_32, 214 ZYDIS_BRANCH_WIDTH_64, 215 }; 216 static const char *str_branch_widths[] = 217 { 218 "W00", 219 "W08", 220 "W16", 221 "W32", 222 "W64", 223 }; 224 static const ZydisInstructionAttributes prefixes[] = { 225 0, 226 ZYDIS_ATTRIB_HAS_BRANCH_TAKEN, 227 }; 228 static const char *str_prefixes[] = 229 { 230 "P00", 231 "PBT", 232 }; 233 static const ZydisAddressSizeHint address_hints[] = 234 { 235 ZYDIS_ADDRESS_SIZE_HINT_NONE, 236 ZYDIS_ADDRESS_SIZE_HINT_16, 237 ZYDIS_ADDRESS_SIZE_HINT_32, 238 ZYDIS_ADDRESS_SIZE_HINT_64, 239 }; 240 static const char *str_address_hints[] = 241 { 242 "AH00", 243 "AH16", 244 "AH32", 245 "AH64", 246 }; 247 static const ZydisOperandSizeHint operand_hints[] = 248 { 249 ZYDIS_OPERAND_SIZE_HINT_NONE, 250 ZYDIS_OPERAND_SIZE_HINT_8, 251 ZYDIS_OPERAND_SIZE_HINT_16, 252 ZYDIS_OPERAND_SIZE_HINT_32, 253 ZYDIS_OPERAND_SIZE_HINT_64, 254 }; 255 static const char *str_operand_hints[] = 256 { 257 "OH00", 258 "OH08", 259 "OH16", 260 "OH32", 261 "OH64", 262 }; 263 264 ZydisEncoderRequest req; 265 ZyanBool all_passed = ZYAN_TRUE; 266 Iterator iter_branches[6] = 267 { 268 { 0, ZYAN_ARRAY_LENGTH(instructions) }, 269 { 0, ZYAN_ARRAY_LENGTH(modes) }, 270 { 0, ZYAN_ARRAY_LENGTH(rels) }, 271 { 0, ZYAN_ARRAY_LENGTH(branch_types) }, 272 { 0, ZYAN_ARRAY_LENGTH(branch_widths) }, 273 { 0, ZYAN_ARRAY_LENGTH(prefixes) }, 274 }; 275 do 276 { 277 ZydisMnemonic mnemonic = instructions[iter_branches[0].value]; 278 ZydisMachineMode mode = modes[iter_branches[1].value]; 279 ZyanU64 rel = rels[iter_branches[2].value]; 280 ZydisBranchType branch_type = branch_types[iter_branches[3].value]; 281 ZydisBranchWidth branch_width = branch_widths[iter_branches[4].value]; 282 ZydisInstructionAttributes prefix = prefixes[iter_branches[5].value]; 283 284 const ZydisEncoderRelInfo *rel_info = ZydisGetRelInfo(mnemonic); 285 ZYAN_ASSERT(rel_info); 286 if (!rel_info->accepts_branch_hints && iter_branches[5].value != 0) 287 { 288 continue; 289 } 290 291 ZYAN_MEMSET(&req, 0, sizeof(req)); 292 req.machine_mode = mode; 293 req.mnemonic = mnemonic; 294 req.prefixes = prefix; 295 req.branch_type = branch_type; 296 req.branch_width = branch_width; 297 req.operand_count = 1; 298 req.operands[0].type = ZYDIS_OPERAND_TYPE_IMMEDIATE; 299 req.operands[0].imm.u = rel; 300 if (mnemonic != ZYDIS_MNEMONIC_JKZD) 301 { 302 req.operand_count = 1; 303 req.operands[0].type = ZYDIS_OPERAND_TYPE_IMMEDIATE; 304 req.operands[0].imm.u = rel; 305 } 306 else 307 { 308 req.operand_count = 2; 309 req.operands[0].type = ZYDIS_OPERAND_TYPE_REGISTER; 310 req.operands[0].reg.value = ZYDIS_REGISTER_K1; 311 req.operands[1].type = ZYDIS_OPERAND_TYPE_IMMEDIATE; 312 req.operands[1].imm.u = rel; 313 } 314 315 char test_name[256]; 316 snprintf(test_name, sizeof(test_name), "%s:%s:%08" PRIX64 ":%s:%s:%s", 317 ZydisMnemonicGetString(mnemonic), 318 str_modes[iter_branches[1].value], 319 rel, 320 str_branch_types[iter_branches[3].value], 321 str_branch_widths[iter_branches[4].value], 322 str_prefixes[iter_branches[5].value]); 323 all_passed &= RunTest(&req, test_name, (mnemonic != ZYDIS_MNEMONIC_JKZD) ? 0 : 1, 324 ZYAN_FALSE); 325 } while (AdvanceIterators(iter_branches, ZYAN_ARRAY_LENGTH(iter_branches))); 326 327 Iterator iter_asz_branches[4] = 328 { 329 { 0, ZYAN_ARRAY_LENGTH(modes) }, 330 { 0, ZYAN_ARRAY_LENGTH(branch_types) }, 331 { 0, ZYAN_ARRAY_LENGTH(branch_widths) }, 332 { 0, ZYAN_ARRAY_LENGTH(address_hints) }, 333 }; 334 do 335 { 336 ZydisMachineMode mode = modes[iter_asz_branches[0].value]; 337 ZydisBranchType branch_type = branch_types[iter_asz_branches[1].value]; 338 ZydisBranchWidth branch_width = branch_widths[iter_asz_branches[2].value]; 339 ZydisAddressSizeHint address_hint = address_hints[iter_asz_branches[3].value]; 340 341 ZYAN_MEMSET(&req, 0, sizeof(req)); 342 req.machine_mode = mode; 343 req.mnemonic = ZYDIS_MNEMONIC_LOOP; 344 req.branch_type = branch_type; 345 req.branch_width = branch_width; 346 req.address_size_hint = address_hint; 347 req.operand_count = 1; 348 req.operands[0].type = ZYDIS_OPERAND_TYPE_IMMEDIATE; 349 req.operands[0].imm.u = 0x55; 350 351 char test_name[256]; 352 snprintf(test_name, sizeof(test_name), "%s:%s:%s:%s:%s", 353 ZydisMnemonicGetString(req.mnemonic), 354 str_modes[iter_asz_branches[0].value], 355 str_branch_types[iter_asz_branches[1].value], 356 str_branch_widths[iter_asz_branches[2].value], 357 str_address_hints[iter_asz_branches[3].value]); 358 all_passed &= RunTest(&req, test_name, 0, ZYAN_FALSE); 359 } while (AdvanceIterators(iter_asz_branches, ZYAN_ARRAY_LENGTH(iter_asz_branches))); 360 361 Iterator iter_osz_branches[3] = 362 { 363 { 0, ZYAN_ARRAY_LENGTH(modes) }, 364 { 0, ZYAN_ARRAY_LENGTH(rels) }, 365 { 0, ZYAN_ARRAY_LENGTH(operand_hints) }, 366 }; 367 do 368 { 369 ZydisMachineMode mode = modes[iter_osz_branches[0].value]; 370 ZyanU64 rel = rels[iter_osz_branches[1].value]; 371 ZydisOperandSizeHint operand_hint = operand_hints[iter_osz_branches[2].value]; 372 373 ZYAN_MEMSET(&req, 0, sizeof(req)); 374 req.machine_mode = mode; 375 req.mnemonic = ZYDIS_MNEMONIC_XBEGIN; 376 req.operand_size_hint = operand_hint; 377 req.operand_count = 1; 378 req.operands[0].type = ZYDIS_OPERAND_TYPE_IMMEDIATE; 379 req.operands[0].imm.u = rel; 380 381 char test_name[256]; 382 snprintf(test_name, sizeof(test_name), "%s:%s:%08" PRIX64 ":%s", 383 ZydisMnemonicGetString(req.mnemonic), 384 str_modes[iter_osz_branches[0].value], 385 rel, 386 str_operand_hints[iter_osz_branches[2].value]); 387 all_passed &= RunTest(&req, test_name, 0, ZYAN_FALSE); 388 } while (AdvanceIterators(iter_osz_branches, ZYAN_ARRAY_LENGTH(iter_osz_branches))); 389 390 return all_passed; 391 } 392 393 static ZyanBool RunRipRelativeTests() 394 { 395 ZydisEncoderRequest req; 396 ZyanBool all_passed = ZYAN_TRUE; 397 398 // Basic test 399 ZYAN_MEMSET(&req, 0, sizeof(req)); 400 req.machine_mode = ZYDIS_MACHINE_MODE_LONG_64; 401 req.mnemonic = ZYDIS_MNEMONIC_XOR; 402 req.operand_count = 2; 403 req.operands[0].type = ZYDIS_OPERAND_TYPE_REGISTER; 404 req.operands[0].reg.value = ZYDIS_REGISTER_RAX; 405 req.operands[1].type = ZYDIS_OPERAND_TYPE_MEMORY; 406 req.operands[1].mem.base = ZYDIS_REGISTER_RIP; 407 req.operands[1].mem.displacement = 0x66666666; 408 req.operands[1].mem.size = 8; 409 all_passed &= RunTest(&req, ZydisMnemonicGetString(req.mnemonic), 1, ZYAN_TRUE); 410 411 // Displacement + immediate 412 ZYAN_MEMSET(&req, 0, sizeof(req)); 413 req.machine_mode = ZYDIS_MACHINE_MODE_LONG_64; 414 req.mnemonic = ZYDIS_MNEMONIC_CMP; 415 req.operand_count = 2; 416 req.operands[0].type = ZYDIS_OPERAND_TYPE_MEMORY; 417 req.operands[0].mem.base = ZYDIS_REGISTER_RIP; 418 req.operands[0].mem.displacement = 0x66666666; 419 req.operands[0].mem.size = 4; 420 req.operands[1].type = ZYDIS_OPERAND_TYPE_IMMEDIATE; 421 req.operands[1].imm.u = 0x11223344; 422 all_passed &= RunTest(&req, ZydisMnemonicGetString(req.mnemonic), 0, ZYAN_TRUE); 423 424 // EIP-relative 425 ZYAN_MEMSET(&req, 0, sizeof(req)); 426 req.machine_mode = ZYDIS_MACHINE_MODE_LONG_64; 427 req.mnemonic = ZYDIS_MNEMONIC_SUB; 428 req.operand_count = 2; 429 req.operands[0].type = ZYDIS_OPERAND_TYPE_MEMORY; 430 req.operands[0].mem.base = ZYDIS_REGISTER_EIP; 431 req.operands[0].mem.displacement = 0x66666666; 432 req.operands[0].mem.size = 4; 433 req.operands[1].type = ZYDIS_OPERAND_TYPE_REGISTER; 434 req.operands[1].reg.value = ZYDIS_REGISTER_EBX; 435 all_passed &= RunTest(&req, ZydisMnemonicGetString(req.mnemonic), 0, ZYAN_TRUE); 436 437 return all_passed; 438 } 439 440 /* ============================================================================================== */ 441 /* Entry point */ 442 /* ============================================================================================== */ 443 444 int main(void) 445 { 446 ZyanBool all_passed = ZYAN_TRUE; 447 ZYAN_PRINTF("Branching tests:\n"); 448 all_passed &= RunBranchingTests(); 449 ZYAN_PRINTF("\nEIP/RIP-relative tests:\n"); 450 all_passed &= RunRipRelativeTests(); 451 ZYAN_PRINTF("\n"); 452 if (!all_passed) 453 { 454 ZYAN_PRINTF("SOME TESTS FAILED\n"); 455 return 1; 456 } 457 458 ZYAN_PRINTF("ALL TESTS PASSED\n"); 459 return 0; 460 } 461 462 /* ============================================================================================== */