7
[原创]使用unicorn对ollvm字符串进行解密
source link: https://bbs.pediy.com/thread-268108.htm
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
使用unicorn对字符串进行解密
偷懒使用unicorn直接将整个so文件load进memory,读取data的数据全是00,修复后也是错误的,我按照leadroyal大佬的脚本修改后是正确的
有时候使用unicorn map后,代码看着没有问题,但是跑起来就报错,可能你需要看看你分配的内存是不是不是1024的倍数
脚本如下:
import
binascii
import
math
import
ida_bytes
import
idaapi
from
capstone
import
*
from
elftools.elf.elffile
import
ELFFile
from
elftools.elf.sections
import
SymbolTableSection
from
keystone
import
*
from
unicorn
import
*
from
unicorn.arm_const
import
*
class
FILFINIT(
object
):
def
__init__(
self
,
file
, mode):
self
.
file
=
file
self
.fd
=
self
.file_init(mode)
self
.elf
=
ELFFile(
self
.fd)
self
.file_size
=
self
.file_size()
self
.data_divs
=
self
.get_data_div()
def
file_init(
self
, mode
=
'rb+'
):
fd
=
open
(
self
.
file
, mode
=
mode)
return
fd
def
file_close(
self
):
self
.fd.close()
def
file_seek_to(
self
, seekto):
self
.fd.seek(seekto,
0
)
def
file_read(
self
, size
=
-
1
):
binary
=
self
.fd.read(size)
return
binary
def
file_write(
self
, data):
self
.fd.write(data)
def
file_size(
self
):
import
os
return
os.path.getsize(
self
.
file
)
def
get_data_div(
self
):
data_divs
=
[]
if
self
.elf:
symtab
=
self
.elf.get_section_by_name(
'.dynsym'
)
assert
isinstance
(symtab, SymbolTableSection)
for
sym
in
symtab.iter_symbols():
# sym.name:str
if
sym.name.startswith(
'.datadiv'
):
data_divs.append(sym.entry.st_value)
return
data_divs
class
UCINIT(
object
):
def
__init__(
self
,
file
, mode, offset
=
0x10000
, stack_size
=
0x10000
, data_size
=
0x10000
):
self
.cs
=
Cs(CS_ARCH_ARM, CS_MODE_THUMB)
self
.fileinfo
=
FILFINIT(
file
, mode)
self
.data_divs
=
self
.uc_filter()
self
.func_start_and_end
=
self
.get_func_start_and_end()
self
.uc
=
unicorn.Uc(UC_ARCH_ARM, UC_MODE_THUMB)
self
.image_base
=
0x10000
self
.offset
=
offset
self
.stack_size
=
stack_size
self
.data_size
=
data_size
self
.image_size
=
(math.ceil(
self
.fileinfo.file_size
/
self
.offset)
+
1
)
*
self
.offset
self
.uc.mem_map(
self
.image_base,
self
.image_size)
self
.init_seg()
# self.uc.mem_write(self.image_base, self.fileinfo.file_read()) # 全文件导入是错误的,不知道为什么
self
.stack_base
=
self
.image_base
+
self
.image_size
+
self
.offset
self
.stack_top
=
self
.stack_base
+
self
.stack_size
-
0x1000
self
.uc.mem_map(
self
.stack_base,
self
.stack_size)
self
.uc.reg_write(UC_ARM_REG_SP,
self
.stack_top)
self
.data_base
=
self
.stack_base
+
self
.stack_size
+
self
.offset
self
.uc.mem_map(
self
.data_base,
self
.data_size)
def
init_seg(
self
):
segs
=
[seg
for
seg
in
self
.fileinfo.elf.iter_segments()
if
seg.header.p_type
=
=
'PT_LOAD'
]
for
seg
in
segs:
self
.uc.mem_write(
self
.image_base
+
seg.header.p_vaddr, seg.data())
def
init_reg(
self
, regs):
index
=
0
for
reg
in
regs:
reg_num
=
66
+
index
self
.uc.reg_write(reg_num, reg)
def
uc_run(
self
, target, end):
targ
=
target
+
self
.image_base
util
=
self
.image_base
+
end
self
.uc.emu_start(targ, util)
def
uc_stop(
self
):
self
.uc.emu_stop()
self
.fileinfo.file_close()
def
register_hook_code(
self
, htype, callback):
self
.uc.hook_add(htype, callback)
def
uc_filter(
self
, size
=
0x2
):
data_divs
=
[]
for
data_div
in
self
.fileinfo.data_divs:
self
.fileinfo.file_seek_to(data_div
-
1
)
data
=
self
.fileinfo.file_read(size)
for
inis
in
self
.cs.disasm(data,
0
):
if
inis.mnemonic
=
=
'bx'
and
inis.op_str
=
=
'lr'
:
continue
else
:
data_divs.append(data_div)
self
.fileinfo.file_seek_to(
0
)
return
data_divs
def
get_func_start_and_end(
self
):
data_divs
=
[]
for
data_div
in
self
.data_divs:
func
=
idaapi.get_func(data_div)
func_start_and_end
=
(data_div, func.end_ea
-
0x2
)
data_divs.append(func_start_and_end)
return
data_divs
def
get_elf_data(
self
):
data_section_header
=
self
.fileinfo.elf.get_section_by_name(
'.data'
).header
print
(
'[+] .data addr {}-{}'
.
format
(
hex
(data_section_header.sh_addr),
hex
(data_section_header.sh_size)))
new_data
=
self
.uc.mem_read(
self
.image_base
+
data_section_header.sh_addr, data_section_header.sh_size)
print
(
'[+] .data binary {}'
.
format
(binascii.hexlify(new_data)))
return
new_data
def
patch_so_data(
self
):
data_section_header
=
self
.fileinfo.elf.get_section_by_name(
'.data'
).header
data_addr
=
data_section_header.sh_addr
# self.fileinfo.file_seek_to(data_addr)
# self.fileinfo.file_write(self.get_elf_data())
new_data
=
self
.get_elf_data()
# new_data: bytearray
print
(
'[+] patch so data addr {}\n {}'
.
format
(
hex
(data_addr), bytes(new_data)))
ida_bytes.patch_bytes(data_addr, bytes(new_data))
def
patch_data_div(
self
):
ks
=
Ks(KS_ARCH_ARM, KS_MODE_THUMB)
for
data_div
in
self
.data_divs:
binary
=
ks.asm(
'bx lr'
)
print
(bytes(binary[
0
]))
# print(struct.pack('B', binary[0]))
print
(
'[+] patch so text .datadiv {}\n {}'
.
format
(
hex
(data_div
-
1
), bytes(binary[
0
])))
ida_bytes.patch_bytes(data_div
-
1
, bytes(binary[
0
]))
def
hook_code(uc: unicorn.Uc, address, size, user_data):
cs
=
Cs(CS_ARCH_ARM, CS_MODE_THUMB)
me
=
uc.mem_read(address, size)
for
code
in
cs.disasm(me, size):
print
(
"[+] Tracing instructions at 0x%x, instructions size = ix%x, inst: %s %s"
%
(
address, size, code.mnemonic, code.op_str))
def
hook_mem_access(uc, access, address, size, value, user_data):
if
access
=
=
UC_MEM_WRITE:
print
(
'[+] Memory is being WRITE at 0x%x, data size = %u, data value = 0x%x'
%
(address, size, value))
else
:
# READ
me
=
uc.mem_read(address, size)
print
(
'[+] Memory is being READ at 0x%x, data size = %u, data value = 0x%s'
%
(
address, size, binascii.hexlify(me)))
if
__name__
=
=
'__main__'
:
print
(
'[+] So file parse starting!'
)
so
=
UCINIT(
'libcrack.so'
,
'rb'
)
# so.get_elf_data()
for
start, end
in
so.func_start_and_end:
print
(
'[+] Data div addr {}-{}'
.
format
(
hex
(start),
hex
(end)))
so.init_reg((
0
,
0
,
0
))
# so.register_hook_code(UC_HOOK_CODE, hook_code)
# so.register_hook_code(UC_HOOK_MEM_READ, hook_mem_access)
# so.register_hook_code(UC_HOOK_MEM_WRITE, hook_mem_access)
so.uc_run(start, end)
so.patch_data_div()
# so.patch_so_data()
# so.get_elf_data()
so.uc_stop()
print
(
'[+] So file run finished!'
)
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK