Skip to content

Commit

Permalink
Add basic AArch32 support across passes
Browse files Browse the repository at this point in the history
  • Loading branch information
antoniofrighetto committed Nov 27, 2024
1 parent 0099419 commit f9913dd
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 26 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class MyConfig(omvll.ObfuscationConfig):

<img src=".github/img/omvll-pipeline.webp" alt="O-MVLL Pipeline" width="100%">

O-MVLL can be used with the Android NDK and an iOS toolchain but **it only supports the AArch64 architecture**.
O-MVLL can be used with the Android NDK and an iOS toolchain. It currently supports AArch64 and ARM architectures.

For more details, please check out the documentation at [obfuscator.re/omvll](https://obfuscator.re/omvll).

Expand Down
6 changes: 6 additions & 0 deletions src/passes/anti-hook/AntiHook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ bool AntiHook::runOnFunction(Function &F) {
if (F.getInstructionCount() == 0)
return false;

const auto &TT = Triple(F.getParent()->getTargetTriple());
if (!TT.isAArch64()) {
SWARN("[{}] Only AArch64 target is supported. Skipping...", name());
return false;
}

if (F.hasPrologueData())
fatalError("Cannot inject a hooking prologue in the function " +
demangle(F.getName().str()) + " since there is one.");
Expand Down
73 changes: 54 additions & 19 deletions src/passes/break-cfg/BreakControlFlow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,61 @@ using namespace llvm;

namespace omvll {

static constexpr size_t InstSize = 4;
static constexpr size_t FunctionAlignment =
static constexpr size_t AArch64InstSize = 4;
static constexpr size_t AArch64FunctionAlignment =
0x20; // Maximum value according to AArch64Subtarget.

static constexpr std::array<std::array<uint8_t, InstSize>, 4> NopInsts = {{
{0x1F, 0x20, 0x03, 0xD5}, // nop
{0xE0, 0x03, 0x00, 0xAA}, // mov x0, x0
{0x42, 0x00, 0xC2, 0x93}, // ror x2, x2, #0
{0xF4, 0x03, 0x14, 0xAA}, // mov x20, x20
}};
static constexpr std::array<std::array<uint8_t, AArch64InstSize>, 4>
AArch64NopInsts = {{
{0x1F, 0x20, 0x03, 0xD5}, // nop
{0xE0, 0x03, 0x00, 0xAA}, // mov x0, x0
{0x42, 0x00, 0xC2, 0x93}, // ror x2, x2, #0
{0xF4, 0x03, 0x14, 0xAA}, // mov x20, x20
}};

static constexpr auto AArch64AsmBreakingStub = R"delim(
// This block must be aligned on 32 bytes
adr x1, #0x10;
ldr x0, [x1, #61];
ldr x1, #16;
blr x1;
ldr x1, #48;
blr x3;
.byte 0xF1, 0xFF, 0xF2, 0xA2;
.byte 0xF8, 0xFF, 0xE2, 0xC2;
)delim";

static constexpr size_t ARMInstSize = 4;
static constexpr size_t ARMFunctionAlignment = 0x10;

static constexpr std::array<std::array<uint8_t, ARMInstSize>, 4> ARMNopInsts = {
{
{0x00, 0xF0, 0x20, 0xE3}, // nop
{0xA0, 0xF0, 0x21, 0xE3}, // mov r0, r0
{0x00, 0x20, 0x82, 0xE3}, // orr r2, r2, #0
{0x02, 0x20, 0xA0, 0xE1}, // mov r2, r2
}};

static constexpr auto ARMAsmBreakingStub = R"delim(
// This block must be aligned on 16 bytes
adr r1, #0x10;
ldr r0, [r1, #61];
ldr r1, #16;
bl r1;
ldr r1, #48;
bl r3;
.byte 0xF0, 0xFF, 0xF0, 0xE7;
.byte 0xFE, 0xFF, 0xFF, 0xE7;
)delim";

bool BreakControlFlow::runOnFunction(Function &F) {
if (F.getInstructionCount() == 0)
return false;

const auto &TT = Triple(F.getParent()->getTargetTriple());
if (!(TT.isAArch64() || TT.isARM()))
return false;

SINFO("[{}] Visiting function {}", name(), F.getName());

ValueToValueMapTy VMap;
Expand All @@ -50,17 +90,12 @@ bool BreakControlFlow::runOnFunction(Function &F) {
F.deleteBody();

Function &Trampoline = F;
const auto AsmBreakingStub = R"delim(
// This block must be aligned on 32 bytes
adr x1, #0x10;
ldr x0, [x1, #61];
ldr x1, #16;
blr x1;
ldr x1, #48;
blr x3;
.byte 0xF1, 0xFF, 0xF2, 0xA2;
.byte 0xF8, 0xFF, 0xE2, 0xC2;
)delim";
const size_t InstSize = TT.isAArch64() ? AArch64InstSize : ARMInstSize;
const size_t FunctionAlignment =
TT.isAArch64() ? AArch64FunctionAlignment : ARMFunctionAlignment;
const auto &NopInsts = TT.isAArch64() ? AArch64NopInsts : ARMNopInsts;
const auto &AsmBreakingStub =
TT.isAArch64() ? AArch64AsmBreakingStub : ARMAsmBreakingStub;

std::unique_ptr<MemoryBuffer> Insts = JIT->jitAsm(AsmBreakingStub, 8);
if (Insts->getBufferSize() % FunctionAlignment)
Expand Down
41 changes: 38 additions & 3 deletions src/test/passes/cfg-flattening/basic-aarch64.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,48 @@
//

// REQUIRES: aarch64-registered-target
// TODO: Add CHECK lines

// RUN: clang -target aarch64-linux-android -O1 -fno-verbose-asm -S %s -o -
// RUN: env OMVLL_CONFIG=%S/config_all.py clang -target aarch64-linux-android -fpass-plugin=%libOMVLL -O1 -fno-verbose-asm -S %s -o -
// RUN: env OMVLL_CONFIG=%S/config_all.py clang -target aarch64-linux-android -fpass-plugin=%libOMVLL -O1 -fno-verbose-asm -S %s -o - | FileCheck --check-prefix=FLAT-ANDROID %s

// RUN: clang -target arm64-apple-ios -O1 -fno-verbose-asm -S %s -o -
// RUN: env OMVLL_CONFIG=%S/config_all.py clang -target arm64-apple-ios -fpass-plugin=%libOMVLL -O1 -fno-verbose-asm -S %s -o -
// RUN: env OMVLL_CONFIG=%S/config_all.py clang -target arm64-apple-ios -fpass-plugin=%libOMVLL -O1 -fno-verbose-asm -S %s -o - | FileCheck --check-prefix=FLAT-IOS %s

// Check for jump table targets setup at the beginning of the function.

// FLAT-ANDROID-LABEL: check_password:
// FLAT-ANDROID: sub sp, sp, #16
// FLAT-ANDROID: movk w4, #1631, lsl #16
// FLAT-ANDROID-NEXT: movk w5, #58789, lsl #16
// FLAT-ANDROID-NEXT: movk w6, #3991, lsl #16
// FLAT-ANDROID-NEXT: movk w7, #14783, lsl #16
// FLAT-ANDROID-NEXT: movk w19, #7850, lsl #16
// FLAT-ANDROID-NEXT: movk w20, #26243, lsl #16
// FLAT-ANDROID-NEXT: movk w21, #9442, lsl #16
// FLAT-ANDROID-NEXT: movk w22, #15558, lsl #16
// FLAT-ANDROID-NEXT: movk w23, #7850, lsl #16
// FLAT-ANDROID-NEXT: movk w24, #26243, lsl #16
// FLAT-ANDROID-NEXT: movk w25, #1631, lsl #16
// FLAT-ANDROID-NEXT: stur w10, [x29, #-4]
// FLAT-ANDROID-NEXT: b .LBB0_5

// FLAT-IOS-LABEL: check_password:
// FLAT-IOS: sub sp, sp, #16
// FLAT-IOS: mov w19, #2181
// FLAT-IOS-NEXT: movk w19, #7850, lsl #16
// FLAT-IOS-NEXT: mov w20, #11601
// FLAT-IOS-NEXT: movk w20, #26243, lsl #16
// FLAT-IOS-NEXT: mov w21, #50895
// FLAT-IOS-NEXT: movk w21, #9442, lsl #16
// FLAT-IOS-NEXT: mov w22, #47994
// FLAT-IOS-NEXT: movk w22, #15558, lsl #16
// FLAT-IOS-NEXT: mov w23, #1804
// FLAT-IOS-NEXT: movk w23, #7850, lsl #16
// FLAT-IOS-NEXT: mov w24, #11818
// FLAT-IOS-NEXT: movk w24, #26243, lsl #16
// FLAT-IOS-NEXT: mov w25, #3737
// FLAT-IOS-NEXT: movk w25, #1631, lsl #16
// FLAT-IOS-NEXT: b LBB0_5

int check_password(const char *passwd, unsigned len) {
if (len != 5) {
Expand Down
32 changes: 29 additions & 3 deletions src/test/passes/cfg-flattening/basic-arm-android.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,34 @@
// REQUIRES: arm-registered-target

// TODO: Add CHECK lines
// RUN: clang -target arm-linux-android -O1 -fno-verbose-asm -S %s -o -
// RUN: env OMVLL_CONFIG=%S/config_all.py clang -target arm-linux-android -fpass-plugin=%libOMVLL -O1 -fno-verbose-asm -S %s -o -
// RUN: clang -target arm-linux-android -O1 -fno-verbose-asm -S %s -o - | FileCheck --check-prefix=NO-FLAT %s
// RUN: env OMVLL_CONFIG=%S/config_all.py clang -target arm-linux-android -fpass-plugin=%libOMVLL -O1 -fno-verbose-asm -S %s -o - | FileCheck --check-prefix=FLAT %s

// Check for jump table targets setup at the beginning of the function.

// NO-FLAT-LABEL: check_password:
// NO-FLAT: mov r2, #0
// NO-FLAT-NEXT: cmp r1, #5
// NO-FLAT-NEXT: bne .LBB0_3
// NO-FLAT-NEXT: ldrb r1, [r0]
// NO-FLAT-NEXT: cmp r1, #79
// NO-FLAT-NEXT: ldrbeq r1, [r0, #1]
// NO-FLAT-NEXT: cmpeq r1, #77
// NO-FLAT-NEXT: beq .LBB0_4

// FLAT-LABEL: check_password:
// FLAT: sub sp, sp, #20
// FLAT-NEXT: str r1, [r11, #-48]
// FLAT-NEXT: ldr r1, .LCPI0_0
// FLAT-NEXT: str r1, [r11, #-36]
// FLAT-NEXT: ldr r12, .LCPI0_1
// FLAT-NEXT: ldr r2, .LCPI0_2
// FLAT-NEXT: ldr r9, .LCPI0_3
// FLAT-NEXT: ldr lr, .LCPI0_10
// FLAT-NEXT: ldr r3, .LCPI0_13
// FLAT-NEXT: ldr r8, .LCPI0_11
// FLAT-NEXT: ldr r4, .LCPI0_12
// FLAT-NEXT: ldr r10, .LCPI0_4
// FLAT-NEXT: b .LBB0_5

int check_password(const char* passwd, unsigned len) {
if (len != 5) {
Expand Down

0 comments on commit f9913dd

Please sign in to comment.