【原創】一個dex脫殼指令碼
轉:http://bbs.pediy.com/showthread.php?p=1459711#post1459711
標 題: 【原創】一個dex脫殼指令碼
作 者: QEver
時 間: 2017-01-03,15:06:50
鏈 接: http://bbs.pediy.com/showthread.php?t=214999
一個ida指令碼,配合kill方法,可以實現脫絕大部分執行於dalvik上的dex殼。至於具體用法,自行領悟吧。
程式碼:
__author__ = 'QEver'
DUMP_FILE_PREFIX = r'd:/'
USER_DEX_FILES_OFFSET = 0x330
LOADED_CLASSES_OFFSET = 0xAC
JAR_NAME_OFFSET = 0x24
SIZE_OF_DEY_HEADER = 0x28
DESC_OFFSET_OF_CLASS_OBJECT = 0x18
METHOD_OFFSET_OF_CLASS_OBJECT = 0x60
SIZE_OF_STRUCT_METHOD = 0x38
import os
import idaapi
import binascii
def read_data(ea, size):
return idaapi.dbg_read_memory(ea, size)
def read_dword(ea):
val = int(binascii.hexlify(idaapi.dbg_read_memory(ea, 4)), 16)
r = (val & 0xff) << 24 | (val & 0xff00) << 8 | (val & 0xff0000) >> 8 | (val & 0xff000000) >> 24
return r
def read_bool(ea):
val = int(binascii.hexlify(idaapi.dbg_read_memory(ea, 1)), 16)
return val
def read_str(ea, max=256):
c = ''
while True:
x = idaapi.dbg_read_memory(ea, 1)
ea = ea + 1
max = max - 1
if x == '\0' or max < 0:
break
c += x
return c
class DvmDex:
def __init__(self, ea):
self.ea = ea
self.pDexFile = read_dword(ea)
self.baseAddr = read_dword(self.pDexFile + 0x2c)
def p(self):
print 'pDexFile = %x' % self.pDexFile
print 'baseAddr = %x' % self.baseAddr
class ClassObject:
def __init__(self, ea):
self.ea = ea
self.desc_addr = read_dword(ea + DESC_OFFSET_OF_CLASS_OBJECT)
def get_descriptor(self):
return read_str(self.desc_addr)
class DexOrJar:
def __init__(self, ea):
self.ea = ea
self.filename = read_dword(ea)
self.isDex = read_bool(ea + 4)
self.pRawDexFile = read_dword(ea + 8)
self.pJarFile = read_dword(ea + 12)
def get_filename(self):
if self.isDex == 0:
return read_str(read_dword(self.pJarFile + JAR_NAME_OFFSET))
return read_str(self.filename)
def get_dvmdex(self):
if self.isDex == 0:
return read_dword(self.pJarFile + JAR_NAME_OFFSET + 4)
return read_dword(self.pRawDexFile + 4)
def p(self):
print 'filename = %s' % read_str(self.filename)
print 'isDex = %d' % self.isDex
print 'pRawDexFile = %x' % self.pRawDexFile
print 'pJarFile = %x' % self.pJarFile
class HashTable:
def __init__(self, ea):
self.ea = ea
self.tableSize = -1
self.numEntries = -1
self.pEntries = None
self.do_init()
def do_init(self):
self.tableSize = read_dword(self.ea)
self.numEntries = read_dword(self.ea + 4)
self.pEntries = read_dword(self.ea + 12)
def get_table_size(self):
return self.tableSize
def get_num_entries(self):
return self.numEntries
def get_pentries(self):
return self.pEntries
def p(self):
print 'tableSize = %d' % self.tableSize
print 'numEntries = %d' % self.numEntries
print 'pEntries = %x' % self.pEntries
class Method:
def __init__(self, ea):
self.ea = ea
def get_name(self):
addr = self.ea + 0x10
return read_str(read_dword(addr))
def get_insns(self):
addr = self.ea + 0x20
return read_dword(addr)
def get_address(self):
return self.ea
def get_gdvm_address():
return idaapi.get_debug_name_ea("gDvm")
def dump_all_dex(prefix=DUMP_FILE_PREFIX):
gdvm = get_gdvm_address()
print '[*] gDvm = 0x%x' % gdvm
user_dex_files = read_dword(gdvm + USER_DEX_FILES_OFFSET)
print '[*] gDvm.user_dex_files = 0x%x' % user_dex_files
ht = HashTable(user_dex_files)
max_size = ht.get_table_size()
size = ht.get_num_entries()
p = ht.get_pentries()
print '[*] Found %s items in Dex Table' % size
for i in range(max_size):
x = read_dword(p)
p += 8
if x == 0:
continue
doj = DexOrJar(x)
print '[*] Dex in Address 0x%x, isDex = %d' % (x, doj.isDex)
addr = doj.get_dvmdex()
name = doj.get_filename()
print '[*] found file : %s , dvmdex = 0x%x' % (name, addr)
dd = DvmDex(addr)
addr = dd.baseAddr
base = addr - SIZE_OF_DEY_HEADER
size = read_dword(addr + 0x20) + SIZE_OF_DEY_HEADER
flag = read_str(base, 3)
if flag != 'dey':
base = addr
size = size = read_dword(addr + 0x20)
print '[*] found odex file = 0x%x <%s>, size = 0x%x' % (base, read_str(base, 7).replace('\n', '.'), size)
name = os.path.basename(name)
path = os.path.join(prefix, name)
print '[*] Write to %s' % path
data = read_data(base, size)
f = open(path, 'wb')
f.write(data)
f.close()
print '[*] Finish Write'
def find_class(name):
gDvm = get_gdvm_address()
loaded_classes = read_dword(gDvm + LOADED_CLASSES_OFFSET)
ht = HashTable(loaded_classes)
max_size = ht.get_table_size()
size = ht.get_num_entries()
p = ht.get_pentries() + 4
print 'Finding for %d items, may take a long time...' % max_size
for i in range(max_size):
x = read_dword(p)
p = p + 8
if x == 0:
continue
c = ClassObject(x)
s = c.get_descriptor()
if s == name:
print '[*] Found Class <%s> : 0x%x' % (name, x)
return x
if s.find(name) != -1:
print '[*] Found Class <%s> : 0x%x' % (s, x)
def list_method(class_addr):
x = ClassObject(class_addr)
print '[*] List All Method of %s' % x.get_descriptor()
m = class_addr + METHOD_OFFSET_OF_CLASS_OBJECT
directMethodCount = read_dword(m)
directMethodTable = read_dword(m + 4)
virtualMethodCount = read_dword(m + 8)
virtualMethodTable = read_dword(m + 12)
for i in range(directMethodCount):
method = Method(directMethodTable)
directMethodTable = directMethodTable + SIZE_OF_STRUCT_METHOD
print method.get_name(), hex(method.get_address())
for i in range(virtualMethodCount):
method = Method(virtualMethodTable)
virtualMethodTable = virtualMethodTable + SIZE_OF_STRUCT_METHOD
print method.get_name()
def list_all_class():
gDvm = get_gdvm_address()
loaded_classes = read_dword(gDvm + LOADED_CLASSES_OFFSET)
ht = HashTable(loaded_classes)
max_size = ht.get_table_size()
size = ht.get_num_entries()
p = ht.get_pentries() + 4
for i in range(max_size):
x = read_dword(p)
p = p + 8
if x == 0:
continue
c = ClassObject(x)
print c.get_descriptor()
if __name__ == '__main__':
#list_all_class()
#find_class('alibaba')
#list_method(class_addr)
dump_all_dex('d:/')
其實指令碼的思想,在2014年阿里安全競賽解題報告裡面,我就已經說的很清楚了。近期簡單整理了程式碼,看到很多人還在糾結dex脫殼問題,就當作新年禮物,給大家分享一下吧。(我認為方法比某qian的xxxhunter靠譜多了~~~~~~~)
本人早已經不做破解相關工作。不過在之前幫朋友的時候,發現現在的殼已經有針對我之前提到過的"kill -19"的防禦措施,深感欣慰(=。=)~不過這條思路是無法防禦的,變通一下方式,就能達到同樣的目的。
總之~方法是死的,人是活的。沒有牛逼的工具,只有牛逼的人~
最後~本Demo只是用於演示破解思路,本人不負責維護,也不會解釋任何使用相關的問題!
相關文章
- 教你如何寫UPX脫殼指令碼指令碼
- 騰訊安全ApkPecker上線DEX-VMP自動化脫殼服務APK
- 一次簡單的脫殼
- upx手動脫殼
- iOS逆向學習之五(加殼?脫殼?)iOS
- 十、iOS逆向之《越獄砸殼/ipa脫殼》iOS
- 一個分詞指令碼分詞指令碼
- Od跟進之脫殼(待完善)
- Android.Hook框架Cydia篇(脫殼機制作)AndroidHook框架
- 一個centos初始化指令碼CentOS指令碼
- 將一個Python指令碼做成一個Windows服務Python指令碼Windows
- 2019年-2023年全球SVOD有指令碼原創內容支出(附原資料表) 指令碼
- 脫殼基礎知識以及簡單應用
- 擼一個 iOS 重簽名指令碼iOS指令碼
- 一個方便 LeetCode 複習的指令碼LeetCode指令碼
- iOS應用程式的脫殼實現原理淺析iOS
- 某IOT蠕蟲病毒分析之UPX脫殼實戰
- 向大家分享一個shell指令碼的坑指令碼
- 一個快速檢視trace的小指令碼指令碼
- PHP 避免同時執行一個指令碼PHP指令碼
- 共享一個iptables的shell指令碼檔案指令碼
- 如何開發一個油猴(TamperMonkey)指令碼指令碼
- 使用Java實現一個JS指令碼引擎JavaJS指令碼
- 手寫指令碼程式碼太累!搞一個生成工具吧指令碼
- 逆向基礎——軟體手動脫殼技術入門
- 【開源】BlackDex,無需環境,Android新姿勢脫殼工具Android
- 分享工作中常用的一個Git指令碼Git指令碼
- 分享一個提高運維效率的 Python 指令碼運維Python指令碼
- 18 個一線工作中常用 Shell 指令碼指令碼
- 一個能夠生成 Markdown 表格的 Bash 指令碼指令碼
- 從0到1編寫一個指令碼引擎指令碼
- 從Android執行時出發,打造我們的脫殼神器Android
- 一鍵部署指令碼指令碼
- 寫一個Python指令碼刪除一個.py檔案的所有註釋Python指令碼
- 我想做一個指令碼更新一些excel表/細胞。指令碼Excel
- [原創] KCP 原始碼分析(上)原始碼
- [原創] KCP 原始碼解析(下)原始碼
- 一個“指令碼執行夯死”問題的分析指令碼
- 從0到1編寫一個JS指令碼引擎JS指令碼