第一步

手机启动frida服务

第二步

手机打开要脱壳的app

第三步编辑hook代码

agent.js

/*
* Author: hluwa <hluwa888@gmail.com>
* HomePage: https://github.com/hluwa
* CreatedTime: 2020/1/7 20:44
* */ var enable_deep_search = false; function verify_by_maps(dexptr, mapsptr) {
var maps_offset = dexptr.add(0x34).readUInt();
var maps_size = mapsptr.readUInt();
for (var i = 0; i < maps_size; i++) {
var item_type = mapsptr.add(4 + i * 0xC).readU16();
if (item_type === 4096) {
var map_offset = mapsptr.add(4 + i * 0xC + 8).readUInt();
if (maps_offset === map_offset) {
return true;
}
}
}
return false;
} function get_dex_real_size(dexptr, range_base, range_end) {
var dex_size = dexptr.add(0x20).readUInt(); var maps_address = get_maps_address(dexptr, range_base, range_end);
if (!maps_address) {
return dex_size;
} var maps_end = get_maps_end(maps_address, range_base, range_end);
if (!maps_end) {
return dex_size;
} return maps_end - dexptr
} function get_maps_address(dexptr, range_base, range_end) {
var maps_offset = dexptr.add(0x34).readUInt();
if (maps_offset === 0) {
return null;
} var maps_address = dexptr.add(maps_offset);
if (maps_address < range_base || maps_address > range_end) {
return null;
} return maps_address;
} function get_maps_end(maps, range_base, range_end) {
var maps_size = maps.readUInt();
if (maps_size < 2 || maps_size > 50) {
return null;
}
var maps_end = maps.add(maps_size * 0xC + 4);
if (maps_end < range_base || maps_end > range_end) {
return null;
} return maps_end;
} function verify(dexptr, range, enable_verify_maps) { if (range != null) {
var range_end = range.base.add(range.size);
// verify header_size
if (dexptr.add(0x70) > range_end) {
return false;
} // In runtime, the fileSize is can to be clean, so it's not trust.
// verify file_size
// var dex_size = dexptr.add(0x20).readUInt();
// if (dexptr.add(dex_size) > range_end) {
// return false;
// } if (enable_verify_maps) { var maps_address = get_maps_address(dexptr, range.base, range_end);
if (!maps_address) {
return false;
} var maps_end = get_maps_end(maps_address, range.base, range_end);
if (!maps_end) {
return false;
}
return verify_by_maps(dexptr, maps_address)
} else {
return dexptr.add(0x3C).readUInt() === 0x70;
}
} return false; } rpc.exports = {
memorydump: function memorydump(address, size) {
return new NativePointer(address).readByteArray(size);
},
switchmode: function switchmode(bool) {
enable_deep_search = bool;
},
scandex: function scandex() {
var result = [];
Process.enumerateRanges('r--').forEach(function (range) {
try {
Memory.scanSync(range.base, range.size, "64 65 78 0a 30 ?? ?? 00").forEach(function (match) { if (range.file && range.file.path
&& (// range.file.path.startsWith("/data/app/") ||
range.file.path.startsWith("/data/dalvik-cache/") ||
range.file.path.startsWith("/system/"))) {
return;
} if (verify(match.address, range, false)) {
var dex_size = get_dex_real_size(match.address, range.base, range.base.add(range.size));
result.push({
"addr": match.address,
"size": dex_size
});
}
}); if (enable_deep_search) {
Memory.scanSync(range.base, range.size, "70 00 00 00").forEach(function (match) {
var dex_base = match.address.sub(0x3C);
if (dex_base < range.base) {
return
}
if (dex_base.readCString(4) != "dex\n" && verify(dex_base, range, true)) {
var real_dex_size = get_dex_real_size(dex_base, range.base, range.base.add(range.size));
result.push({
"addr": dex_base,
"size": real_dex_size
});
}
})
} else {
if (range.base.readCString(4) != "dex\n" && verify(range.base, range, true)) {
// console.log("range.base=" + range.base);
var real_dex_size = get_dex_real_size(range.base, range.base, range.base.add(range.size));
// console.log("range.base=" + range.base + ", real_dex_size=" + real_dex_size);
result.push({
"addr": range.base,
"size": real_dex_size
});
}
} } catch (e) {
}
}); return result;
}
};

第四步

运行脱壳代码

# Author: hluwa <hluwa888@gmail.com>
# HomePage: https://github.com/hluwa
# CreatedTime: 2020/1/7 20:57
import hashlib
import os
import random
import sys try:
from shutil import get_terminal_size as get_terminal_size
except:
try:
from backports.shutil_get_terminal_size import get_terminal_size as get_terminal_size
except:
pass import click
import frida
import logging
import traceback logging.basicConfig(level=logging.INFO,
format="%(asctime)s %(levelname)s %(message)s",
datefmt='%m-%d/%H:%M:%S') banner = """
----------------------------------------------------------------------------------------
____________ ___________ ___ ______ _______ _______
| ___| ___ \_ _| _ \/ _ \ | _ \ ___\ \ / / _ \
| |_ | |_/ / | | | | | / /_\ \______| | | | |__ \ V /| | | |_ _ _ __ ___ _ __
| _| | / | | | | | | _ |______| | | | __| / \| | | | | | | '_ ` _ \| '_ \
| | | |\ \ _| |_| |/ /| | | | | |/ /| |___/ /^\ \ |/ /| |_| | | | | | | |_) |
\_| \_| \_|\___/|___/ \_| |_/ |___/ \____/\/ \/___/ \__,_|_| |_| |_| .__/
| |
|_|
https://github.com/hluwa/FRIDA-DEXDump
----------------------------------------------------------------------------------------
""" md5 = lambda bs: hashlib.md5(bs).hexdigest() def show_banner():
try:
if get_terminal_size().columns >= len(banner.splitlines()[1]):
for line in banner.splitlines():
click.secho(line, fg=random.choice(['bright_red', 'bright_green', 'bright_blue', 'cyan', 'magenta']))
except:
pass def get_all_process(device, pkgname):
return [process for process in device.enumerate_processes() if pkgname in process.name] def search(api):
"""
""" matches = api.scandex()
for info in matches:
click.secho("[DEXDump] Found: DexAddr={}, DexSize={}"
.format(info['addr'], hex(info['size'])), fg='green')
return matches def dump(pkg_name, api, mds=None):
"""
"""
if mds is None:
mds = []
matches = api.scandex()
for info in matches:
try:
bs = api.memorydump(info['addr'], info['size'])
md = md5(bs)
if md in mds:
click.secho("[DEXDump]: Skip duplicate dex {}<{}>".format(info['addr'], md), fg="blue")
continue
mds.append(md)
if not os.path.exists("./" + pkg_name + "/"):
os.mkdir("./" + pkg_name + "/")
if bs[:4] != b"dex\n":
bs = b"dex\n035\x00" + bs[8:]
with open(pkg_name + "/" + info['addr'] + ".dex", 'wb') as out:
out.write(bs)
click.secho("[DEXDump]: DexSize={}, DexMd5={}, SavePath={}/{}/{}.dex"
.format(hex(info['size']), md, os.getcwd(), pkg_name, info['addr']), fg='green')
except Exception as e:
click.secho("[Except] - {}: {}".format(e, info), bg='yellow') def stop_other(pid, processes):
try:
for process in processes:
if process.pid == pid:
os.system("adb shell \"su -c 'kill -18 {}'\"".format(process.pid))
else:
os.system("adb shell \"su -c 'kill -19 {}'\"".format(process.pid))
except:
pass def choose(pid=None, pkg=None, spawn=False, device=None):
if pid is None and pkg is None:
target = device.get_frontmost_application()
return target.pid, target.identifier for process in device.enumerate_processes():
if (pid and process.pid == pid) or (pkg and process.name == pkg):
if not spawn:
return process.pid, process.name
else:
pkg = process.name
break if pkg and spawn and device:
pid = device.spawn(pkg)
device.resume(pid)
return pid, pkg
raise Exception("Cannot found <{}> process".format(pid)) if __name__ == "__main__":
show_banner() try:
device = frida.get_usb_device()
except:
device = frida.get_remote_device() if not device:
click.secho("[Except] - Unable to connect to device.", bg='red')
exit() pid = -1
pname = ""
try:
pid, pname = choose(device=device)
except Exception as e:
click.secho("[Except] - Unable to inject into process: {} in \n{}".format(e, traceback.format_tb(
sys.exc_info()[2])[-1]), bg='red')
exit()
print(pname)
processes = get_all_process(device, pname) mds = []
for process in processes:
logging.info("[DEXDump]: found target [{}] {}".format(process.pid, process.name))
stop_other(process.pid, processes)
session = device.attach(process.pid)
path = os.path.dirname(sys.argv[0])
path = path if path else "."
script = session.create_script(open(path + "/agent.js").read())
script.load()
dump(pname, script.exports, mds=mds)
script.unload()
session.detach()
exit()

APP脱壳方法三的更多相关文章

  1. 快速定位 Android APP 当前页面的三种方法(Activity / Fragment)

    方法一.通过adb命令打印当前页面: Android 如何快速定位当前页面是哪个Activity or Fragment (1)查看当前Activity :adb shell "dumpsy ...

  2. Android常见App加固厂商脱壳方法的整理

    目录 简述(脱壳前学习的知识.壳的历史.脱壳方法) 第一代壳 第二代壳 第三代壳 第N代壳 简述 Apk文件结构 Dex文件结构 壳史 壳的识别 Apk文件结构 Dex文件结构 壳史 第一代壳 Dex ...

  3. App元素定位三种方法

    来自博客: http://testingpai.com/article/1595507262082 以下方法操作前必须确保有手机设备连入电脑,检测是否有手机连入命令 adb devices 第一种:A ...

  4. 彩贝网app破解登入参数(涉及app脱壳,反编译java层,so层动态注册,反编译so层)

    一.涉及知识点 app脱壳 java层 so层动态注册 二.抓包信息 POST /user/login.html HTTP/1.1 x-app-session: 1603177116420 x-app ...

  5. Android APP压力测试(三)之Monkey日志自动分析脚本

    Android APP压力测试(三) 之Monkey日志自动分析脚本 前言 上次说要分享Monkey日志的分析脚本,这次贴出来分享一下,废话不多说,请看正文. [目录] 1.Monkey日志分析脚本 ...

  6. Android抓包方法(三)之Win7笔记本Wifi热点+WireShark工具

    Android抓包方法(三) 之Win7笔记本Wifi热点+WireShark工具 前言 做前端测试,基本要求会抓包,会分析请求数据包,查看接口是否调用正确,数据返回是否正确,问题产生是定位根本原因等 ...

  7. Django 2.0.1 官方文档翻译: 编写你的第一个 Django app,第三部分(Page 8)

    编写你的第一个 Django app,第三部分(Page 8)转载请注明链接地址 本页教程接前面的第二部分.我们继续开发 web-poll app,我们会专注于创建公共接口上 -- "视图& ...

  8. Android应用APP脱壳笔记

    [TOC] 天下游 模拟定位技术点简析 通过代码分析初步猜测模拟定位用到的几处技术点: 获取了Root权限 通过反射获取 android.os.ServiceManager 对应的函数 getServ ...

  9. 总结Themida / Winlicense加壳软件的脱壳方法

    总结下Themida/ Winlicense (TM /  WL) 的脱壳方法. 1, 查看壳版本,这个方法手动也可以,因为这个壳的版本号是写在程序里面的,在解压后下断点即可查看,这里有通用的脚本,我 ...

随机推荐

  1. 云计算openstack核心组件——cinder存储服务(11)

    一.cinder 介绍:   理解 Block Storage 操作系统获得存储空间的方式一般有两种: 通过某种协议(SAS,SCSI,SAN,iSCSI 等)挂接裸硬盘,然后分区.格式化.创建文件系 ...

  2. Thread、ThreadLocal源码解析

    今天来看一下Thread和ThreadLocal类的源码. 一.Thread (1)首先看一下线程的构造方法,之后会说每种参数的用法,而所有的构造函数都会指向init方法 //空构造创建一个线程 Th ...

  3. Powershell编程基础-004-for语句的使用

    For循环在PowerShell中也称为For语句. 同其他编程语言类似 当指定条件的值为True时,此循环以代码块的形式执行语句,另,For后面接(;;)代表恒为真! 实例1:用于执行指定次数的语句 ...

  4. linux学习(一)认识阿里云

    一.简介 阿里云,全球领先的云计算服务平台,阿里巴巴集团旗下公司.致力于打造公共.开放的云计算服务平台.提供云服务器ECS.关系型数据库服务RDS.开放存储服务OSS.内容分发网络CDN.对象存储OS ...

  5. 有没有异常处理翻车过的,绩效还被打了C

    絮叨 因为程序异常处理问题,就在前几天龙叔的服务挂了几秒钟. 完了,马上季度末打绩效,竟然在这里翻车了,心如刀绞啊. 虽然没有影响到用户体验,但是找到问题并解决掉问题是工程师日常追求之一. 作为一个优 ...

  6. MySql WorkBench 导入sql文件 中文出现乱码

    在workbench中导入sql文件. 查看系统的编码. 导入sql文件时出现了如下警告.但是文件是UTF-8.由于包含中文,使用latin1编码方式会出现乱码. 选择UTF-8,出现错误. 不知道什 ...

  7. POI和easyExcel

    POI与easyExcel 这个东西一般用来做什么? 将用户信息导出为Excel表格(导出数据) 将Excel表中的信息录入到网站数据库(比如一些习题上传) 在开发过程中会遇到对Excel的处理,比如 ...

  8. OpenMP变量作用域【private】【shared】

    (1) privateprivate子句将一个或多个变量声明为线程的私有变量.每个线程都有它自己的变量私有副本,其他线程无法访问.即使在并行区域外有同名的共享变量,共享变量在并行区域内不起任何作用,并 ...

  9. Java知识系统回顾整理01基础05控制流程01if

    一.if if(表达式1){ 表达式2: } 如果表达式1的值是true, 就执行表达式2 public class HelloWorld { public static void main(Stri ...

  10. centos配置WordPress(Apache+mysql+php)

    .安装Apache 安装命令:sudo yum install httpd 启动服务:sudo service httpd start 在浏览器输入IP地址,正常应该显示Apache的欢迎页面 如果提 ...