diff --git a/courgette/encode_decode_unittest.cc b/courgette/encode_decode_unittest.cc index 6c52e20e7a1bb0..cec0bfa9180f8a 100644 --- a/courgette/encode_decode_unittest.cc +++ b/courgette/encode_decode_unittest.cc @@ -83,7 +83,7 @@ TEST_F(EncodeDecodeTest, PE) { TEST_F(EncodeDecodeTest, PE64) { std::string file = FileContents("chrome64_1.exe"); - TestAssembleToStreamDisassemble(file, 809635); + TestAssembleToStreamDisassemble(file, 810090); } TEST_F(EncodeDecodeTest, Elf_Small) { diff --git a/courgette/rel32_finder_x64.cc b/courgette/rel32_finder_x64.cc index b9b04582304ca4..324317fce47b78 100644 --- a/courgette/rel32_finder_x64.cc +++ b/courgette/rel32_finder_x64.cc @@ -56,27 +56,60 @@ void Rel32FinderX64::Find(const uint8_t* start_pointer, if (p[0] == 0x0F && (p[1] & 0xF0) == 0x80) { // Jcc long form if (p[1] != 0x8A && p[1] != 0x8B) // JPE/JPO unlikely rel32 = p + 2; - } else if (p[0] == 0xFF && (p[1] == 0x15 || p[1] == 0x25)) { - // rip relative CALL/JMP + } else if ((p[0] == 0xFF && + (p[1] == 0x15 || p[1] == 0x25)) || + ((p[0] == 0x89 || p[0] == 0x8B || p[0] == 0x8D) && + (p[1] & 0xC7) == 0x05)) { + // 6-byte instructions: + // [2-byte opcode] [disp32]: + // Opcode + // FF 15: call QWORD PTR [rip+disp32] + // FF 25: jmp QWORD PTR [rip+disp32] + // + // [1-byte opcode] [ModR/M] [disp32]: + // Opcode + // 89: mov DWORD PTR [rip+disp32],reg + // 8B: mov reg,DWORD PTR [rip+disp32] + // 8D: lea reg,[rip+disp32] + // ModR/M : MMRRRMMM + // MM = 00 & MMM = 101 => rip+disp32 + // RRR: selects reg operand from [eax|ecx|...|edi] rel32 = p + 2; is_rip_relative = true; } } - // TODO(etiennep): Many rip mov/lea variants are not detected. Experiment, - // fix and combine logic. + // TODO(huangs): Maybe skip checking prefixes, + // and let 6-byte instructions take care of this? if (p + 7 <= end_pointer) { - if ((p[0] & 0xFB) == 0x48 && // Dst reg : 48/4C [rax-rdi]/[r8-r15] - p[1] == 0x8D && // LEA - (p[2] & 0xC7) == 0x05) { // Dst reg : [05,0D,...3D] = - // [rax,rbx,...,rdi]/[r8,r9,...,r15] - // LEA dst, QWORD [rip + rel32] - rel32 = p + 3; - is_rip_relative = true; - } else if ((p[0] & 0xFB) == 0x48 && // Dst reg : 48/4C [rax-rdi]/[r8-r15] - p[1] == 0x8B && // MOV - (p[2] & 0xC7) == 0x05) { // Dst reg : [05,0D,...3D] = - // [rax,rbx,...,rdi]/[r8,r9,...,r15] - // MOV dst, QWORD PTR[rip + rel32] + if (((p[0] & 0xF2) == 0x40 || p[0] == 0x66) && + (p[1] == 0x89 || p[1] == 0x8B || p[1] == 0x8D) && + (p[2] & 0xC7) == 0x05) { + // 7-byte instructions: + // [REX.W prefix] [1-byte opcode] [ModR/M] [disp32] + // REX Prefix : 0100WR0B + // W: 0 = Default Operation Size + // 1 = 64 Bit Operand Size + // R: 0 = REG selects from [rax|rcx|...|rdi]. + // 1 = REG selects from [r9|r10|...|r15]. + // B: ModR/M r/m field extension (not used). + // Opcode + // 89: mov QWORD PTR [rip+disp32],reg + // 8B: mov reg,QWORD PTR [rip+disp32] + // 8D: lea reg,[rip+disp32] + // ModR/M : MMRRRMMM + // MM = 00 & MMM = 101 => rip+disp32 + // RRR: selects reg operand + // + // 66 [1-byte opcode] [ModR/M] [disp32] + // Prefix + // 66: Operand size override + // Opcode + // 89: mov WORD PTR [rip+disp32],reg + // 8B: mov reg,WORD PTR [rip+disp32] + // 8D: lea reg,[rip+disp32] + // ModR/M : MMRRRMMM + // MM = 00 & MMM = 101 = rip+disp32 + // RRR selects reg operand from [ax|cx|...|di] rel32 = p + 3; is_rip_relative = true; } diff --git a/courgette/testdata/rel32_x64_01.txt b/courgette/testdata/rel32_x64_01.txt index 340701d8429f38..656365cfb2112b 100644 --- a/courgette/testdata/rel32_x64_01.txt +++ b/courgette/testdata/rel32_x64_01.txt @@ -55,8 +55,16 @@ Program: 00 004010C2: 4C 8D 3D 00 00 00 lea r15,[rip+00000000] 00 - 004010C9: 5D pop ebp - 004010CA: C3 ret + 004010C9: 66 8B 05 00 00 00 mov ax,[rip+00000000] + 00 + 004010D0: 66 8B 3D 00 00 00 mov di,[rip+00000000] + 00 + 004010D7: 66 8D 05 00 00 00 lea ax,[rip+00000000] + 00 + 004010DE: 66 8D 3D 00 00 00 lea di,[rip+00000000] + 00 + 004010E5: 5D pop ebp + 004010E6: C3 ret Abs32: @@ -79,10 +87,10 @@ Expected: 1069 106F 1075 -# 107B Not yet detected. -# 1081 Not yet detected. -# 1087 Not yet detected. -# 108D Not yet detected. +107B +1081 +1087 +108D 1094 109B 10A2 @@ -90,4 +98,8 @@ Expected: 10B0 10B7 10BE -10C5 \ No newline at end of file +10C5 +10CC +10D3 +10DA +10E1 \ No newline at end of file diff --git a/courgette/testdata/rel32_x64_02.txt b/courgette/testdata/rel32_x64_02.txt index fd6fd94f0af5cc..541b1f95c41f97 100644 --- a/courgette/testdata/rel32_x64_02.txt +++ b/courgette/testdata/rel32_x64_02.txt @@ -58,7 +58,15 @@ Program: 00 004010C2: 4C 8D 3D 00 00 00 lea r15,[rip+00000000] 00 - 004010C9: 5D pop ebp + 004010C9: 66 8B 05 00 00 00 mov ax,[rip+00000000] + 00 + 004010D0: 66 8B 3D 00 00 00 mov di,[rip+00000000] + 00 + 004010D7: 66 8D 05 00 00 00 lea ax,[rip+00000000] + 00 + 004010DE: 66 8D 3D 00 00 00 lea di,[rip+00000000] + 00 + 004010C9: 5D pop ebp 004010CA: C3 ret Abs32: @@ -88,10 +96,10 @@ Expected: 1069 106F 1075 -# 107B Not yet detected. -# 1081 Not yet detected. -# 1087 Not yet detected. -# 108D Not yet detected. +107B +1081 +1087 +108D 1094 109B 10A2 @@ -99,4 +107,8 @@ Expected: # 10B0 # 10B7 10BE -10C5 \ No newline at end of file +10C5 +10CC +10D3 +10DA +10E1 \ No newline at end of file diff --git a/courgette/testdata/rel32_x64_03.txt b/courgette/testdata/rel32_x64_03.txt index 5a1c12cf8ba620..b91a56219eed85 100644 --- a/courgette/testdata/rel32_x64_03.txt +++ b/courgette/testdata/rel32_x64_03.txt @@ -70,5 +70,5 @@ Expected: 1056 106E 1074 # x64 rip ignores .text boundaries (target likely in .data section). -# 1086 Not yet detected. -# 108C Not yet detected. \ No newline at end of file +1086 +108C \ No newline at end of file