SkillAgentSearch skills...

UnsupportedInstructionsLiftingToLLVM

Using Zydis and LLVM to lift unsupported instructions to LLVM-IR

Install / Use

/learn @LLVMParty/UnsupportedInstructionsLiftingToLLVM
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

UnsupportedInstructionsLiftingToLLVM

Using Zydis and LLVM to lift assembly instructions to LLVM-IR as inline assembly calls. This is meant to be used when lifting a virtual machine protection or obfuscated code, in a context where the lifter doesn't provide the semantic for a specific instruction and supports only a subset of the machine registers.

This PoC shows how to lift some assembly instructions assuming that the lifter supports only the general purpose registers. The general purpose registers (implicitly or explicitly) read by the instruction are loaded from the virtual registers context and fed as arguments to the inline assembly call. The general purpose registers (implicitly or explicitly) written by the instruction are obtained by the inline assembly call result and stored on the virtual registers context.

The support to the clobber constraints is only sketched (e.g. ~{memory} is currently naïvely supported detecting if the instruction is executing an implicit or hidden memory access). By default the inline assembly calls are marked as having sideeffect, but ideally that should be used only when the constraints list is not explicitly mentioning some effects of the assembly instruction. Changes to the stack pointer are currently unsupported as they mess with the local stack frame.

Sample output (unoptimized)

; ModuleID = 'Module'
source_filename = "Module"

%ContextTy = type { %RegisterR, %RegisterR, %RegisterR, %RegisterR, %RegisterR, %RegisterR, %RegisterR, %RegisterR, %RegisterR, %RegisterR, %RegisterR, %RegisterR, %RegisterR, %RegisterR, %RegisterR, %RegisterR }
%RegisterR = type { %RegisterW }
%RegisterW = type { i64 }
%RegisterB = type { i8, i8, i8, i8, i8, i8, i8, i8 }
%IAOutTy = type { i32, i32, i32, i32 }
%IAOutTy.0 = type { i32, i32 }
%IAOutTy.1 = type { i64, i64 }
%IAOutTy.2 = type { i64, i64 }

; Function Attrs: alwaysinline
define void @Unsupported_pop(%ContextTy* %0) #0 {
  %2 = call i64 asm sideeffect inteldialect "pop rsp", "={rsp},~{memory}"() #1
  %3 = getelementptr inbounds %ContextTy, %ContextTy* %0, i64 0, i32 6, i32 0
  %4 = bitcast %RegisterW* %3 to %RegisterB*
  %5 = getelementptr inbounds %RegisterB, %RegisterB* %4, i64 0, i32 0
  %6 = bitcast i8* %5 to i64*
  store i64 %2, i64* %6, align 4
  ret void
}

; Function Attrs: alwaysinline
define void @Unsupported_std(%ContextTy* %0) #0 {
  call void asm sideeffect inteldialect "std", "~{flags},~{dirflag}"() #1
  ret void
}

; Function Attrs: alwaysinline
define void @Unsupported_add(%ContextTy* %0) #0 {
  %2 = getelementptr inbounds %ContextTy, %ContextTy* %0, i64 0, i32 1, i32 0
  %3 = bitcast %RegisterW* %2 to %RegisterB*
  %4 = getelementptr inbounds %RegisterB, %RegisterB* %3, i64 0, i32 0
  %5 = bitcast i8* %4 to i8*
  %6 = load i8, i8* %5, align 1
  %7 = getelementptr inbounds %ContextTy, %ContextTy* %0, i64 0, i32 0, i32 0
  %8 = bitcast %RegisterW* %7 to %RegisterB*
  %9 = getelementptr inbounds %RegisterB, %RegisterB* %8, i64 0, i32 1
  %10 = bitcast i8* %9 to i8*
  %11 = load i8, i8* %10, align 1
  %12 = call i8 asm sideeffect inteldialect "add $0, $1", "=r,r,0,~{flags}"(i8 %6, i8 %11) #1
  %13 = getelementptr inbounds %ContextTy, %ContextTy* %0, i64 0, i32 0, i32 0
  %14 = bitcast %RegisterW* %13 to %RegisterB*
  %15 = getelementptr inbounds %RegisterB, %RegisterB* %14, i64 0, i32 1
  %16 = bitcast i8* %15 to i8*
  store i8 %12, i8* %16, align 1
  ret void
}

; Function Attrs: alwaysinline
define void @Unsupported_fsqrt(%ContextTy* %0) #0 {
  call void asm sideeffect inteldialect "fsqrt", "~{fpsr}"() #1
  ret void
}

; Function Attrs: alwaysinline
define void @Unsupported_fsincos(%ContextTy* %0) #0 {
  call void asm sideeffect inteldialect "fsincos", "~{fpsr}"() #1
  ret void
}

; Function Attrs: alwaysinline
define void @Unsupported_fstp(%ContextTy* %0) #0 {
  %2 = getelementptr inbounds %ContextTy, %ContextTy* %0, i64 0, i32 0, i32 0
  %3 = bitcast %RegisterW* %2 to %RegisterB*
  %4 = getelementptr inbounds %RegisterB, %RegisterB* %3, i64 0, i32 0
  %5 = bitcast i8* %4 to i64*
  %6 = load i64, i64* %5, align 4
  call void asm sideeffect inteldialect "fstp qword ptr ds:[$0], st0", "r,~{fpsr}"(i64 %6) #1
  ret void
}

; Function Attrs: alwaysinline
define void @Unsupported_add.1(%ContextTy* %0) #0 {
  %2 = getelementptr inbounds %ContextTy, %ContextTy* %0, i64 0, i32 1, i32 0
  %3 = bitcast %RegisterW* %2 to %RegisterB*
  %4 = getelementptr inbounds %RegisterB, %RegisterB* %3, i64 0, i32 0
  %5 = bitcast i8* %4 to i32*
  %6 = load i32, i32* %5, align 4
  %7 = getelementptr inbounds %ContextTy, %ContextTy* %0, i64 0, i32 0, i32 0
  %8 = bitcast %RegisterW* %7 to %RegisterB*
  %9 = getelementptr inbounds %RegisterB, %RegisterB* %8, i64 0, i32 0
  %10 = bitcast i8* %9 to i32*
  %11 = load i32, i32* %10, align 4
  %12 = call i32 asm sideeffect inteldialect "add $0, $1", "=r,r,0,~{flags}"(i32 %6, i32 %11) #1
  %13 = getelementptr inbounds %ContextTy, %ContextTy* %0, i64 0, i32 0, i32 0
  %14 = bitcast %RegisterW* %13 to %RegisterB*
  %15 = getelementptr inbounds %RegisterB, %RegisterB* %14, i64 0, i32 0
  %16 = bitcast i8* %15 to i32*
  store i32 %12, i32* %16, align 4
  ret void
}

; Function Attrs: alwaysinline
define void @Unsupported_cpuid(%ContextTy* %0) #0 {
  %2 = getelementptr inbounds %ContextTy, %ContextTy* %0, i64 0, i32 0, i32 0
  %3 = bitcast %RegisterW* %2 to %RegisterB*
  %4 = getelementptr inbounds %RegisterB, %RegisterB* %3, i64 0, i32 0
  %5 = bitcast i8* %4 to i32*
  %6 = load i32, i32* %5, align 4
  %7 = getelementptr inbounds %ContextTy, %ContextTy* %0, i64 0, i32 2, i32 0
  %8 = bitcast %RegisterW* %7 to %RegisterB*
  %9 = getelementptr inbounds %RegisterB, %RegisterB* %8, i64 0, i32 0
  %10 = bitcast i8* %9 to i32*
  %11 = load i32, i32* %10, align 4
  %12 = call %IAOutTy asm sideeffect inteldialect "cpuid", "={eax},={ecx},={edx},={ebx},{eax},{ecx}"(i32 %6, i32 %11) #1
  %13 = getelementptr inbounds %ContextTy, %ContextTy* %0, i64 0, i32 0, i32 0
  %14 = bitcast %RegisterW* %13 to %RegisterB*
  %15 = getelementptr inbounds %RegisterB, %RegisterB* %14, i64 0, i32 0
  %16 = bitcast i8* %15 to i32*
  %17 = extractvalue %IAOutTy %12, 0
  store i32 %17, i32* %16, align 4
  %18 = getelementptr inbounds %ContextTy, %ContextTy* %0, i64 0, i32 2, i32 0
  %19 = bitcast %RegisterW* %18 to %RegisterB*
  %20 = getelementptr inbounds %RegisterB, %RegisterB* %19, i64 0, i32 0
  %21 = bitcast i8* %20 to i32*
  %22 = extractvalue %IAOutTy %12, 1
  store i32 %22, i32* %21, align 4
  %23 = getelementptr inbounds %ContextTy, %ContextTy* %0, i64 0, i32 3, i32 0
  %24 = bitcast %RegisterW* %23 to %RegisterB*
  %25 = getelementptr inbounds %RegisterB, %RegisterB* %24, i64 0, i32 0
  %26 = bitcast i8* %25 to i32*
  %27 = extractvalue %IAOutTy %12, 2
  store i32 %27, i32* %26, align 4
  %28 = getelementptr inbounds %ContextTy, %ContextTy* %0, i64 0, i32 1, i32 0
  %29 = bitcast %RegisterW* %28 to %RegisterB*
  %30 = getelementptr inbounds %RegisterB, %RegisterB* %29, i64 0, i32 0
  %31 = bitcast i8* %30 to i32*
  %32 = extractvalue %IAOutTy %12, 3
  store i32 %32, i32* %31, align 4
  ret void
}

; Function Attrs: alwaysinline
define void @Unsupported_rdtsc(%ContextTy* %0) #0 {
  %2 = call %IAOutTy.0 asm sideeffect inteldialect "rdtsc", "={eax},={edx}"() #1
  %3 = getelementptr inbounds %ContextTy, %ContextTy* %0, i64 0, i32 0, i32 0
  %4 = bitcast %RegisterW* %3 to %RegisterB*
  %5 = getelementptr inbounds %RegisterB, %RegisterB* %4, i64 0, i32 0
  %6 = bitcast i8* %5 to i32*
  %7 = extractvalue %IAOutTy.0 %2, 0
  store i32 %7, i32* %6, align 4
  %8 = getelementptr inbounds %ContextTy, %ContextTy* %0, i64 0, i32 3, i32 0
  %9 = bitcast %RegisterW* %8 to %RegisterB*
  %10 = getelementptr inbounds %RegisterB, %RegisterB* %9, i64 0, i32 0
  %11 = bitcast i8* %10 to i32*
  %12 = extractvalue %IAOutTy.0 %2, 1
  store i32 %12, i32* %11, align 4
  ret void
}

; Function Attrs: alwaysinline
define void @Unsupported_div(%ContextTy* %0) #0 {
  %2 = getelementptr inbounds %ContextTy, %ContextTy* %0, i64 0, i32 0, i32 0
  %3 = bitcast %RegisterW* %2 to %RegisterB*
  %4 = getelementptr inbounds %RegisterB, %RegisterB* %3, i64 0, i32 0
  %5 = bitcast i8* %4 to i64*
  %6 = load i64, i64* %5, align 4
  %7 = getelementptr inbounds %ContextTy, %ContextTy* %0, i64 0, i32 3, i32 0
  %8 = bitcast %RegisterW* %7 to %RegisterB*
  %9 = getelementptr inbounds %RegisterB, %RegisterB* %8, i64 0, i32 0
  %10 = bitcast i8* %9 to i64*
  %11 = load i64, i64* %10, align 4
  %12 = getelementptr inbounds %ContextTy, %ContextTy* %0, i64 0, i32 2, i32 0
  %13 = bitcast %RegisterW* %12 to %RegisterB*
  %14 = getelementptr inbounds %RegisterB, %RegisterB* %13, i64 0, i32 0
  %15 = bitcast i8* %14 to i64*
  %16 = load i64, i64* %15, align 4
  %17 = call %IAOutTy.1 asm sideeffect inteldialect "div $4", "={rax},={rdx},{rax},{rdx},r,~{flags}"(i64 %6, i64 %11, i64 %16) #1
  %18 = getelementptr inbounds %ContextTy, %ContextTy* %0, i64 0, i32 0, i32 0
  %19 = bitcast %RegisterW* %18 to %RegisterB*
  %20 = getelementptr inbounds %RegisterB, %RegisterB* %19, i64 0, i32 0
  %21 = bitcast i8* %20 to i64*
  %22 = extractvalue %IAOutTy.1 %17, 0
  store i64 %22, i64* %21, align 4
  %23 = getelementptr inbounds %ContextTy, %ContextTy* %0, i64 0, i32 3, i32 0
  %24 = bitcast %RegisterW* %23 to %RegisterB*
  %25 = getelementptr inbounds %RegisterB, %RegisterB* %24, i64 0, i32 0
  %26 = bitcast i8* %25 to i64*
  %27 = extractvalue %IAOutTy.1 %17, 1
  store i64 %27, i64* %26, align 4
  ret void
}

; Function Attrs: alwaysinline
define void @Unsupported_add.2(%ContextTy* %0) #0 {
  %2 = getelementptr inbounds %ContextTy, %ContextTy* %0, i64 0, i32 1, i32 0
  %3 = bitcast %RegisterW* %2 to %RegisterB*
  %4 = getelementptr inbounds %RegisterB, %RegisterB* %3, i64 0, i32 0
  %5 = bitcast i8* %4 to i64*
  %6 = load i64, i64* %5, align 4
  %7 = getelementptr inbounds %ContextTy, %ContextTy* %0, i64 0, i32 0, i32 0
  %8 = bitcast %RegisterW* %7 to %RegisterB*
  %9 = 

Related Skills

View on GitHub
GitHub Stars30
CategoryCustomer
Updated8mo ago
Forks4

Languages

C++

Security Score

67/100

Audited on Jul 7, 2025

No findings