Skip to content

Instantly share code, notes, and snippets.

@mrexodia
Created September 30, 2024 22:33
Show Gist options
  • Save mrexodia/632561f6e96706be2a40ffab23282c28 to your computer and use it in GitHub Desktop.
Save mrexodia/632561f6e96706be2a40ffab23282c28 to your computer and use it in GitHub Desktop.
String decryption with icicle
import pefile
import icicle
# Section flags
IMAGE_SCN_MEM_SHARED = 0x10000000
IMAGE_SCN_MEM_EXECUTE = 0x20000000
IMAGE_SCN_MEM_READ = 0x40000000
IMAGE_SCN_MEM_WRITE = 0x80000000
class PEmulator:
def __init__(self, path: str):
self.path = path
self.pe = pefile.PE(path)
# Instantiate the emulator
machine = self.pe.FILE_HEADER.Machine
arch_name = {
pefile.MACHINE_TYPE['IMAGE_FILE_MACHINE_AMD64']: "x86_64",
pefile.MACHINE_TYPE['IMAGE_FILE_MACHINE_I386']: "x86",
}.get(self.pe.FILE_HEADER.Machine)
assert arch_name is not None, f"Unsupported machine: {machine}"
self.ic = icicle.Icicle(arch_name, shadow_stack=False)
self.image_base = self.map_image(self.pe)
self.entry_point = self.pe.OPTIONAL_HEADER.AddressOfEntryPoint + self.image_base
self.allocation_base = 0x100000
self.stack_size = 0x10000
self.stack_base = self.allocate(self.stack_size)
def page_align(self, size: int) -> int:
return (size + 0xFFF) & ~0xFFF
def allocate(self, size: int, protection=icicle.MemoryProtection.ExecuteReadWrite) -> int:
assert self.allocation_base & 0xFFF == 0
addr = self.allocation_base
size = self.page_align(size)
self.allocation_base += size
self.ic.mem_map(addr, size, protection)
return addr
def map_image(self, pe: pefile.PE, *, image_base: int = 0):
assert pe.FILE_HEADER.Machine == self.pe.FILE_HEADER.Machine, "Architecture mismatch"
image_size = pe.OPTIONAL_HEADER.SizeOfImage
section_alignment = pe.OPTIONAL_HEADER.SectionAlignment
assert section_alignment == 0x1000, f"Unsupported section alignment {hex(section_alignment)}"
if image_base == 0:
image_base = pe.OPTIONAL_HEADER.ImageBase
self.ic.mem_map(image_base, image_size, icicle.MemoryProtection.NoAccess)
mapped_image = pe.get_memory_mapped_image(ImageBase=image_base)
self.ic.mem_write(image_base, mapped_image)
for section in pe.sections:
name = section.Name.rstrip(b"\0")
mask = section_alignment - 1
rva = (section.VirtualAddress_adj + mask) & ~mask
va = image_base + rva
size = self.page_align(section.Misc_VirtualSize)
flags = section.Characteristics
assert flags & IMAGE_SCN_MEM_SHARED == 0, "Shared sections are not supported"
assert flags & IMAGE_SCN_MEM_READ != 0, "Non-readable sections are not supported"
execute = flags & IMAGE_SCN_MEM_EXECUTE
write = flags & IMAGE_SCN_MEM_WRITE
protect = icicle.MemoryProtection.ReadOnly
if write:
if execute:
protect = icicle.MemoryProtection.ExecuteReadWrite
else:
protect = icicle.MemoryProtection.ReadWrite
elif execute:
protect = icicle.MemoryProtection.ExecuteRead
self.ic.mem_protect(va, size, protect)
print(f"Mapping section '{name.decode()}' {hex(rva)}[{hex(rva)}] -> {hex(va)} as {protect}")
header_size = pe.sections[0].VirtualAddress_adj
self.ic.mem_protect(image_base, header_size, icicle.MemoryProtection.ReadOnly)
return image_base
def run(self, address: int):
self.ic.reg_write("rip", address)
self.ic.reg_write("rsp", self.stack_base + self.stack_size - 0x18)
status = self.ic.run()
print(status, self.ic.exception_code, hex(self.ic.exception_value))
print(hex(self.ic.reg_read("rip")))
def main():
pass
if __name__ == "__main__":
emu = PEmulator("5cecb26a3f33c24b92a0c8f6f5175da0664b21d7c4216a41694e4a4cad233ca8")
temp = emu.allocate(0x5000)
emu.ic.reg_write("rcx", 0x140010a90)
emu.ic.reg_write("rdx", temp)
emu.run(0x14000c1e4)
data = emu.ic.mem_read(temp, 0x5000).rstrip(b"\0")
print(data)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment