UnsupportedInstructionsLiftingToLLVM
Using Zydis and LLVM to lift unsupported instructions to LLVM-IR
Install / Use
/learn @LLVMParty/UnsupportedInstructionsLiftingToLLVMREADME
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
openhue
342.0kControl Philips Hue lights and scenes via the OpenHue CLI.
sag
342.0kElevenLabs text-to-speech with mac-style say UX.
weather
342.0kGet current weather and forecasts via wttr.in or Open-Meteo
tweakcc
1.5kCustomize Claude Code's system prompts, create custom toolsets, input pattern highlighters, themes/thinking verbs/spinners, customize input box & user message styling, support AGENTS.md, unlock private/unreleased features, and much more. Supports both native/npm installs on all platforms.
