越狱hook

工具

checkra 越狱
安装ipa的工具impactor
越狱ipa,32位,iOS10.x
越狱ipa,64位,iOS11.2-11.3.1

MonkeyDev官网
frida-ios-dump
Theos 生成 TWeak项目
导出.decrypted头文件 class-dump
dylib项目开发

syslogd Utilities
yololib

反汇编

Cydia 软件

1
2
openssh
cycript

砸壳 dumpdecrypted

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 查看有哪些证书
security find-identity -v -p codesigning

# 签名文件
codesign --force --verify --verbose --sign "iPhone Distribution: HOLLYCRMBEIJING TECHNOLOGY CO.LTD. (T4V6H9AMFL)" dumpdecrypted.dylib

# 拷贝 dumpdecrypted.dylib 到手机app沙盒路径
scp dumpdecrypted.dylib root@192.168.31.121:/var/mobile/Containers/Data/Application/092E7298-56A7-4E68-BF45-CCBC93806DD7/Documents

# 砸壳,进入待砸APP的沙盒目录
DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib 程序WeChat安装路径

# 查看是否加密 cryptid 1加密,2没加密
otool -l WeChat.ipa|grep cry

MonkeyDev

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 安装 theos
sudo git clone --recursive https://github.com/theos/theos.git /opt/theos

# 安装 ldid
brew install ldid
brew install dpkg
# iproxy 端口映射
brew install usbmuxd

xcode-select -p

# 安装 MonkeyDev
sudo /bin/sh -c "$(curl -fsSL https://raw.githubusercontent.com/AloneMonkey/MonkeyDev/master/bin/md-install)"
# 更新
sudo /bin/sh -c "$(curl -fsSL https://raw.githubusercontent.com/AloneMonkey/MonkeyDev/master/bin/md-update)"

Logos Tweak 项目

1
2
3
// 项目工程目录 Package/LibraryMobileSubstrate/DynamicLibraries/.plist 文件修改 Bundles 添加微信的 bundleid

根据手机信息修改 Build Settings 配置 User-Defined 栏目里面的IP,密码等

cycript

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 找到运行中的程序
cycript -p WeChat

# cy 查看沙盒路径
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]

#
[NSBundle mainBundle].bundleIdentifier
#
UIApp.keyWindow.recursiveDescription().toString()
#
[[[UIWindow keyWindow] rootViewController] _printHierarchy].toString()
#
[[UIApp keyWindow] _autolayoutTrace].toString()

# 获取地址的内容: #0x13491fb90
# 打印成员变量: *#0x13491fb90
# 查询当前页面的某个类 choose(UIButton)

debugserver

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# debugserver 路径: 找到对应的 DeveloperDiskImage.dmg 里面的 /usr/bin/debugserver
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport

# debugserver 手机路径
/Developer/usr/bin/debugserver

# 拷贝到电脑,重新赋权,然后拷贝到手机 /usr/bin/ 目录下
codesign -s - --entitlements en.plist -f debugserver

# 开启手机端调试
debugserver localhost:12345 –a WeChat

# 手机端口映射 mac端口 手机端口
iproxy 1234 12345

# Mac端 lldb 连接 debugserver
process connect connect://127.0.0.1:1234

文件 en.plist

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.backboardd.debugapplications</key>
<true/>
<key>com.apple.backboardd.launchapplications</key>
<true/>
<key>com.apple.frontboard.debugapplications</key>
<true/>
<key>com.apple.frontboard.launchapplications</key>
<true/>
<key>com.apple.springboard.debugapplications</key>
<true/>
<key>com.apple.system-task-ports</key>
<true/>
<key>get-task-allow</key>
<true/>
<key>platform-application</key>
<true/>
<key>run-unsigned-code</key>
<true/>
<key>task_for_pid-allow</key>
<true/>
</dict>
</plist>

dylib

微信步数修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
CHDeclareClass(WCDeviceStepObject); // declare class  

CHOptimizedMethod(0, self, unsigned int, WCDeviceStepObject, m7StepCount) // hook method (with no arguments and no return value)
{
// write code here ...

return 98888; //随意改数
}

CHConstructor // code block that runs immediately upon load
{
@autoreleasepool
{
CHLoadLateClass(WCDeviceStepObject);
CHHook(0, WCDeviceStepObject,m7StepCount);
}
}

runtime

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@selector()
-(bool)respondsToSelector:(SEL)
- (IMP)methodForSelector:(SEL)aSelector
+ (IMP)instanceMethodForSelector:(SEL)aSelector

//获取Ivar的名称
const char *ivar_getName(Ivar v);
//获取Ivar的类型编码,
const char *ivar_getTypeEncoding(Ivar v)
//通过变量名称获取类中的实例成员变量
Ivar class_getInstanceVariable(Class cls, const char *name)
//通过变量名称获取类中的类成员变量
Ivar class_getClassVariable(Class cls, const char *name)
//获取指定类的Ivar列表及Ivar个数
Ivar *class_copyIvarList(Class cls, unsigned int *outCount)
//获取实例对象中Ivar的值
id object_getIvar(id obj, Ivar ivar)
//设置实例对象中Ivar的值
void object_setIvar(id obj, Ivar ivar, id value)

breakpoint

1
2
3
br list | delete | 
br set -a 地址
br set -n 方法名称

lldb

1
2
3
4
5
frame info

image lookup -rn sendDidClick

expression -l objc -O -- 🙂

汇编 assembly

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# isa 的指向
x86: isa & 0x00007ffffffffff8ULL
arm: isa & 0x0000000ffffffff8ULL

# 查看 寄存器
register read

# 打印 objc_msgSend(id, SEL) 的参数
po $arg1 # 接收消息的对象
po (SEL)$arg2 # 执行消息的方法
po $arg3 # 方法的参数

# arm64
x0 返回值
fp x29 高地址 栈顶
lr x30 函数最后一条指令的下一条指令
sp x31 底地址 栈底
pc x32 当前要执行的指令


# 指令

# 入栈指令: x29, x30 存到 sp-0x10, sp=sp-0x10
stp x29, x30, [sp, #-0x10]!
# x0 的数据传递到 [SP, #0x8] 地址指向的存储空间
str x0, [SP, #0x8]

# 出栈指令:
ldp x29, x30, [sp, #-0x10]!
# [x6, #0x80] 的地址值指向的值赋给 x5
ldr x5, [x6, #0x80]

# x2 的值赋给 x1
mov x1, x2

# add 加, sub 减, and 与, orr 或, eor 异或


# ?寻找 x8 内 22464 的
adrp x8, 22464

#
bl

参考链接

https://www.jianshu.com/p/24c6cb55fb0d

https://www.jianshu.com/p/9487e194fdc9

https://www.jianshu.com/p/64cf03a79caa

https://www.jianshu.com/p/bdbac933c1be

adb

adb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 连接手机
adb shell

# 拷贝桌面文件到手机 Download目录下
adb push ~/Desktop/t.txt /sdcard/Download/

# 从手机拷贝文件到桌面
adb pull /sdcard/Download/t.txt ~/Desktop/

# 端口转发 (frida -R 可以连接)
adb forward tcp:27042 tcp:27042

# 同一wifi下调试,开启手机 5555-5585 的奇数端口,然后在 connect 手机ip
adb tcpip 5555
adb connect 192.168。31.203:5555

android 其他有用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# 获取事件
getevent
# 查看事件
getevent -p
# 找到含有 0035(宽) 0036(高) 的 /dev/input/event (event名字不同), 监听 event
getevent /dev/input/event1 | grep -e "0035" -e "0036"


# 安装【卸载 uninstall 】
install test.apk
# 设备型号
getprop ro.product.model
# 系统版本
getprop ro.build.version.release

# 截屏
screencap /sdcard/test.png

# 模拟 输入 3:Home, 4:Back, 23:确定 26:Power, 66:Enter, 82:Menu, 111:Esc, 223:熄屏, 224:亮屏
input keyevent 82
input text XXXX
input tap 200 100
input swipe 200 800 200 300

# 后台服务
service list

# 输出 视图结构
uiautomator dump

# dumpsys 命令
# 所有命令
dumpsys -l
# 当前 视图名称
dumpsys window | grep mCurrentFocus
# ui 层级信息
dumpsys SurfaceFlinger
# activity 相关
dumpsys activity oom
dumpsys activity activities
dumpsys activity top
dumpsys activity intents
# 按包名 查看 (View Hierarchy)
dumpsys activity -p com.tencent.wework
# 包的信息
dumpsys package com.tencent.wework


# am 命令
# 强制关闭
am force-stop com.tencent.wework
# 打开微信
am start -n com.tencent.mm/.ui.LauncherUI
am start -n com.tencent.wework/.launch.LaunchSplashActivity
# 打电话
am start -a android.intent.action.CALL -d tel:10086


# pm 命令
# -3 第三方包名,-s 系统包名,-f 查看安装来源
pm list package
# 查看包名的安装路径
pm path com.tencent.wework
# 查看安装包的信息
pm dump com.tencent.wework
# 清空包数据
pm clear com.tencent.wework

# 查看可以 debuger 的
run-as com.tencent.mm

# wm 命令 屏幕尺寸、dpi
wm size
wm density


# ----
pm grant [packageName] android.permission.WRITE_SECURE_SETTINGS

# 查看辅助服务
settings get secure enabled_accessibility_services

# 开启辅助服务
settings put secure enabled_accessibility_services com.maruko.qwdemo/com.maruko.qwdemo.service.StatusAccessibilityService

#
settings put secure accessibility_enabled 1

frida

官网

https://frida.re/

安装

1
2
3
4
5
pip3 install frida-tools
# 安装指定版本
pip3 install frida==14.2.18
# 更新
sudo pip3 install --upgrade frida

python 加载 js 文件

文件f.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import sys
import frida

js_file_name = 'hook.js'
process_name = "com.tencent.wework"

def on_message(message, data):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)

def get_js_code():
js_file = open(js_file_name, 'r')
return js_file.read()

if __name__ == '__main__':
# get_usb_device get_remote_device
process = frida.get_usb_device().attach(process_name)
script = process.create_script(get_js_code())

script.on('message', on_message)
script.load()

sys.stdin.read()
1
2
# 运行
python3 f.py

文件 hook.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
Java.perform(function () {
console.log('hook js...')

var JavaString = Java.use('java.lang.String');
var JavaUri = Java.use('android.net.Uri');
var androidView = Java.use('android.view.View')
var androidAct = Java.use('android.app.Activity')
var androidContext = Java.use('android.content.Context')
var androidClass = Java.use('java.lang.Class')
var Intent = Java.use('android.content.Intent')

var wwMain = Java.use('com.tencent.wework.launch.WwMainActivity')
var wwAct = Java.use('com.tencent.wework.login.controller.LoginWxAuthActivity')
var wwBut = Java.use('com.tencent.wework.common.views.ConfigurableTextView')
var wwEt = Java.use('android.widget.LinearLayout')
var wwActMenu = Java.use('com.tencent.wework.friends.controller.FriendAddMenu3rdActivity')
var wwActSearch = Java.use('com.tencent.wework.friends.controller.WechatFriendAddSearchActivity')


// 按名称 Java heap 里面 className 匹配
Java.choose("com.tencent.wework.friends.controller.WechatFriendAddSearchActivity", {
"onMatch":function(instance){
console.log("[*] Instance found: " + instance.toString());
},
"onComplete":function() {
console.log("[*] Finished heap search")
}
});

// 实现 Intent init 的4个重载方法
var intentInit1 = Intent.$init.overload('android.content.Intent')
intentInit1.implementation = function(intent){
console.log('Intent1 ...')
var ins = intentInit1.call(this, intent)
send(this)
return ins
}
var intentInit2 = Intent.$init.overload('java.lang.String')
intentInit2.implementation = function(intent){
console.log('Intent2 ...')
var ins = intentInit2.call(this, intent)
send(this)
send(intent)
return ins
}
var intentInit3 = Intent.$init.overload('java.lang.String','android.net.Uri')
intentInit3.implementation = function(intent, uri){
console.log('Intent3 ...')
var ins = intentInit3.call(this, intent, uri)
send(this)
return ins
}
var intentInit4 = Intent.$init.overload('android.content.Context','java.lang.Class')
intentInit4.implementation = function(intent, cls){
console.log('Intent4 ...')
var ins = intentInit4.call(this, intent, cls)
send(this)
send(this.getAction())
// send(this.getExtras().toString())

send(intent)
send(cls)
return ins
}


// 实现每个 Activity 的 onResume 方法
var onResume = androidAct.onResume
onResume.implementation = function(){
onResume.call(this)
// this.onResume()

let className = this.getClass().toString()
console.log(this)
console.log(className)
console.log('onResume ...')

// 企微 主页
if(className.indexOf('WwMainActivity') > -1){

}

}

});

android/android

1
2


1
2
# 跑程序
nohup app_process -Djava.class.path=/sdcard/Download/classes3.dex /system/bin/ --nice-name=classes shell.Main &
1
2
3
4
5
6
7
8
9
10
// 打开微信
startActivity(getPackageManager().getLaunchIntentForPackage("com.tencent.mm"));


// 打开浏览器
Intent i = new Intent("android.intent.action.VIEW");
String pkg = "me.li2.test";
String cls = "me.li2.test.Activity_A";
i.setComponent(new ComponentName(pkg, cls));
startActivity(i);