逆向 笔记

MD5提取结果通常是32位,不受明文长度影响;
Base64编码结果末尾通常会出现一或二个等于符号,受明文长度影响;
一长串无规律数字与字母组合的字符大概率是AES、DES、SHA相关加密;
SHA1加密结果值为40位,不受明文长度影响;
SHA256加密结果值为64位,不受明文长度影响;
另外, AES、RSA等对称和非对称加密都喜欢将结果值用Base64进行编码,这样易于传递;
如果你看到一长串字符里出现+号、\号和末尾的=号,那大概率就是上一行描述的加密算法加密后又进行了Base64编码的结果;
但要注意的是32位的字符串不一定是MD5摘要结果, 64位的也不一定是SHA加密结果

Reres

1.扩展程序管理
在这里插入图片描述
逆向 笔记_第1张图片
浏览器

  • btoa():任意值转为 Base64 编码
  • atob():Base64 编码转为原来的值
  • 非ASCII码要转码再base64 encodeURIComponent decodeURIComponent

NodeJs

var b64encode = new Buffer.from("JavaScript").toString("base64");
console.log(b64encode)
var b64decode = new Buffer.from(b64encode,'base64').toString();
console.log(b64decode)

刷机后时间错误、网络不可访问:

adb shell settings put global captive_portal_http_url https://www.google.cn/generate_204
adb shell settings put global captive_portal_https_url https://www.google.cn/generate_204
adb shell settings put global ntp_server 1.hk.pool.ntp.org
adb shell reboot

Android7以上安装证书:

openssl x509 -inform PEM -subject_hash_old -in cacert.pem 
 ren charles.pem  2e355b8b.0
 adb push 2e355b8b.0 /sdcard/
 adb shell
 su
 mount -o rw,remount /system
 mv /sdcard/2e355b8b.0 /system/etc/security/cacerts/
 chmod 644 /system/etc/security/cacerts/2e355b8b.0
reboot

计算cer证书hash值

openssl x509 -inform PEM -subject_hash_old -in /Users/wiliam/temp/FiddlerRoot.cer -inform der

“证书安装程序停止运行”解决方法:

手机关机后按电源键和音量- 选择recovery启动
adb root
adb remount
adb push 2e355b8b.0 sdcard/Download/
adb shell
cp sdcard/Download/2e355b8b.0 /data/adb/modules/movecert/system/etc/security/cacerts/
ls /data/adb/modules/movecert/system/etc/security/cacerts/
chown root:root /data/adb/modules/movecert/system/etc/security/cacerts/*
chmod 644 /data/adb/modules/movecert/system/etc/security/cacerts/*
chcon u:object_r:system_file:s0 /data/adb/modules/movecert/system/etc/security/cacerts/*
reboot

PC和手机需要安装版本一致的Frida版本,还要注意手机系统架构

查看手机系统架构:(adb shell中运行)

bullhead:/ # getprop ro.product.cpu.abi
arm64-v8a
pip install frida==12.8.0 frida_tools==5.3.0 objection==1.8.4
Kali 环境
frida          14.2.17
frida-tools    9.2.4


手机 /data/local/tmp/目录下
frida-server-14.2.17-android-arm64 re.frida.server

chmod 777 frida-server-12.11.17-android-arm64
./frida-server-12.11.17-android-arm64

确定frida已建立联系:
frida ps -U

查看手机进程
frida-ps -U

查询网址:https://github.com/frida/frida/releases
在对应版本Frida中查找Frida-tools版本即可

安装frida ide智能提示
(安装nvm,使用node 12的版本)

$ git clone git://github.com/oleavr/frida-agent-example.git
$ cd frida-agent-example/
$ npm install
$ frida -U -f com.example.android --no-pause -l _agent.js

在frida-agent-example/下新建文件夹编写frida脚本

hello world

frida -U -l hello_world.js com.android.bluetooth
(-U为USB, -l为脚本所在路径)
exit 或 Ctrl+D 退出


REPL(Read-Eval-Print Loop)“交互式解释器”或“交互式编程环境”

frida-ps -U | grep 'settings'
objection -g com.android.settings explore

JADX开启反混淆后类名并非原来的类名

方法分为静态方法和实例方法,应当分别从类和实例处重载

frida如何查看HashMap

var Map = Java.use('java.util.HashMap');
var args_map = Java.cast(m, Map);
console.log(args_map.toString());

wallbreaker的使用

7z x frida-server-12.8.0-android-arm64.xz
adb push frida-server-12.8.0-android-arm64 /data/local/tmp
git clone https://github.com/hluwa/Wallbreaker.git ~/.objection/plugins/Wallbreaker
objection -g com.qiyi.video.lite explore -P ~/.objection/plugins/
plugin wallbreaker objectsearch 类名 (每次运行句柄会变化)
plugin wallbreaker objectdump 0x31ba

objection日志文件是: ~/.objection/objection.log, 可以删除, 方便查看下次的内容.

objection在APP启动时hook

objection -g 包名 explore -s "android hooking watch class 类 --dump-args --dump-backtrace --dump-return"

objection attach app
https://github.com/sensepost/objection/issues/335

╰─$ frida -Uf "cn.kuwo.player" -l anti_frida_detection.js
╰─$ frida-ps -Ua
  PID  Name          Identifier
5  ------------  -----------------------
18833   酷我音乐      cn.kuwo.player
╰─$ objection -g 18833 explore -P ~/.objection/plugins/

或者
╰─$ objection -g `frida-ps -Ua | grep kuwo | awk '{print $1}'` explore -P ~/.objection/plugins/ -c objection_batch_hook.txt

如何使用objection去批量hook和trace?
逆向 笔记_第2张图片

frida在APP启动时hook------send()相当于console.log()

import frida  # 导入frida模块
import sys  # 导入sys模块

jscode = """
    Java.perform(function(){  
        var c = Java.use("com.tencent.news.tad.common.e.d"); // 类的加载路径

        c.ˆ.overload('java.lang.String').implementation = function(str){   
            send(str);
            var r = this.ˆ(str);
            send("success2");
            send(r);
            return r;
        };

    });
"""


def on_message(message, data):  # js中执行send函数后要回调的函数
    if message["type"] == "send":
        print("[*] {0}".format(message["payload"]))
    else:
        print(message)


process = frida.get_usb_device()

pid = process.spawn(['com.tencent.news'])  # spawn后app会进入空白页面卡住
session = process.attach(pid)  # 依据进程号attach进程
script = session.create_script(jscode)  # 创建js脚本
script.on('message', on_message)  # 加载回调函数,也就是js中执行send函数规定要执行的python函数
script.load()  # 加载脚本
process.resume(pid)  # 从空白页面恢复运行
sys.stdin.read()

静态函数直接use class然后调用方法,非静态函数需要先choose实例然后调用

Frida疑问:
内部类
new Class() {
	public int fun(){}
}
fun没有static为什么可以直接use class然后hook方法?继承

frida怎么实例化枚举类

使用Frida时,想要打印Java对象的内容,可以使用谷歌的gson包
https://bbs.pediy.com/thread-259186.htm

用wallbreaker找到想要查看属性的实例:

objection -g com.tencent.news explore -P ~/.objection/plugins/

com.tencent.news on (google: 8.1.0) [usb] # plugin wallbreaker objectsearch com.tencent.news.tad.business.manager.a                     
[0x5bda]: com.tencent.news.tad.business.manager.a@3b47eab

查看实例的属性:plugin wallbreaker objectdump 0x5bda
逆向 笔记_第3张图片
查找相关类,找到实例句柄

com.tencent.news on (google: 8.1.0) [usb] # 

 - [ ] android heap search instances com.tencent.news.utils.sp.f$b

                                                                                                          
Using exsiting matches for com.tencent.news.utils.sp.f$b. Use --fresh flag for new instances.
Handle  Class                                                    toString()
------  --------------------------------------------  ----------------------
0x71e6  com.tencent.news.utils.sp.f$b  com.tencent.news.utils.sp.f$b@714da6f

用Objection使用实例句柄调用带参数的方法

com.tencent.news on (google: 8.1.0) [usb] # android heap evaluate 0x71e6                                                                
(The handle at `0x71e6` will be available as the `clazz` variable.)
var r = clazz.getString("taid", "");  
console.log(r);                                                                                                                         
JavaScript capture complete. Evaluating...
Handle 0x71e6 is to class com.tencent.news.utils.sp.f$b
0101869F9B239EB76E4D33C8D47D3D64B96FE17E74A91CC327CA1F452E8F00F2ECE8FB329612972826BF88AC

构造Context

var current_application = Java.use('android.app.ActivityThread').currentApplication();
var context = current_application.getApplicationContext();

构造Long类型

Java.use('java.lang.Long').parseLong.overload('java.lang.String').call(Java.use('java.lang.Long'), "3373342304")

查看Long类型的值

console.log(long.value);

打印调用栈

console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));

打印字符串数组

// fastjson在大部分app中都有集成
var FastJson = Java.use('com.alibaba.fastjson.JSON');
console.log(FastJson.toJSONString(builder));
let arr_len = Java.vm.getEnv().getArrayLength(retval);
console.log("数组长度:", arr_len)
for (let i=0; i

frida rpc base64例子

import time

import frida  # 导入frida模块

with open('test2.js') as f:
    jscode = f.read()

process = frida.get_usb_device()

pid = process.spawn(['com.android.settings'])  # spawn后app会进入空白页面卡住,
process.resume(pid)  # resume恢复app的运行
time.sleep(1)

# pid = process.get_process('com.android.settings').pid  # 不重启app

print('进程号:', pid)
session = process.attach(pid)  # 加载进程号
script = session.create_script(jscode)  # 创建js脚本
script.load()  # 加载脚本
api = script.exports
r = api.get()
print(r)

function get(){
    var base64;
    Java.perform(function(){

        var StringClass = Java.use("java.lang.String");
        var byteArray = StringClass.$new("Hello World").getBytes();
//        console.log(byteArray)
//        console.log(JSON.stringify(byteArray))

        var b = Java.use("java.util.Base64").$new().getEncoder();
        base64 = b.encodeToString(byteArray)
//        console.log(base64)

    })
    return base64

}
rpc.exports={
    get:get
}
}
rpc.exports={
    get:get
}

Frida Debug

frida -Uf "air.tv.douyu.android" -l hook_all_map.js --runtime=v8 --debug --no-pause
//frida代码添加
//在chrome开发者工具打开node调试

//python脚本
script = process.create_script(f.read(), runtime='v8')
process.enable_debugger()

Maskgisk安装MagiskHide Props Config模块,实现全局可调试

adb shell //adb进入命令行模式
su //切换至超级用户
magisk resetprop ro.debuggable 1  //设置debuggable
stop;start; //一定要通过该方式重启

查看效果 为1则正常
#adb shell "getprop ro.debuggable"
1

重启后会重置为0!

为Android Studio安装smalidea插件
https://bitbucket.org/JesusFreke/smali/downloads/

启动调试界面
adb shell am start -D -n 包名/.MainActivity
查找进程号
adb shell ps | grep 包名
使用 jdwp 转发端口:
adb forward tcp:端口 jdwp:进程号
创建remote调试

Android Studio打开apk, 直接Debug运行. 进入后打断点, 操作手机触发断点

如果断点不生效, 卸载app后再Debug (被玩坏了???)

高效学习smali:

Android Studio安装java2smali插件,
Build -> Compile to smali, 就能把java代码转成smali 

Xpose不重启方案

mount -o rw,remount -t auto /
替换/system/framework/XposedBridge.jar
chmod 777 XposedBridge.jar

查看当前Activity

adb shell dumpsys activity top | grep ACTIVITY

非标准端口启用 frida-server和objection

/data/local/tmp/frida-server-12.8.0-android-arm64 -l 0.0.0.0:3353
objection -N -h 172.16.90.221 -p 3353 -g com.r0syue.nativetest explore

还原被名称粉碎机制破坏的函数名()
(一调用会报错app无法运行???)

# c++filt _Z54Java_com_r0syue_nativetest_MainActivity_stringFromJNI2P7_JNIEnvP8_jobject
Java_com_r0syue_nativetest_MainActivity_stringFromJNI2(_JNIEnv*, _jobject*)

查看静态注册的JNI函数在哪个so文件:

解压apk, 到lib目录下:
grep -ril "函数名" *
例: grep -ril "getQdsfWithTimestampJNI" *
(r 递归目录  i 忽略大小写   l 只输出文件名)

动态注册的JNI函数需要靠hook定位:

git clone https://github.com/lasting-yang/frida_hook_libart.git
frida -U -l hook_RegisterNatives.js -f com.qiyi.video.lite --no-pause

Andoid Studio

点击Run后AS会安装app-debug.apk.
手机应用的apk位置在/data/app/包名-base64字符串/base.apk

╰─$ adb shell pm list package | grep music
package:com.tencent.qqmusic
╰─$ adb shell pm path com.tencent.qqmusic
package:/data/app/~~741Xbz7-KBWlNG71ZIFGZQ==/com.tencent.qqmusic-PANj6LE3nCBuwNqarbWvtQ==/base.apk
╰─$ adb pull /data/app/~~741Xbz7-KBWlNG71ZIFGZQ==/com.tencent.qqmusic-PANj6LE3nCBuwNqarbWvtQ==/base.apk qqmusic.apk
/data/app/~~741Xbz7-KBWlNG71ZIFGZQ==/com.tencent.qqmusic-PANj6LE3...: 1 file pulled, 0 skipped. 35.2 MB/s (157805747 bytes in 4.280s)

AS Logcat日志过滤
点击“create New Logcat Filter”, 起个名字,在Log Tag输入

^(?!.*(libc|StudioTransport|GRPC|AudioTrack|SoundPool|Zygote|libprocessgroup)).*$
adb查看应用所占用内存

adb shell dumpsys meminfo -a com.tencent.reading

APK在手机上的路径
/data/app/包名***/base.apk

adb shell pm list packages
adb shell pm path com.xd.fp.ad
adb pull /data/app/~~MLGJJLICrscYTrNxIXdzdw==/com.xd.fp.ad-M2awbsAciEqDHes2KrfURg==/base.apk ~/Desktop/KUbuntu/派对之星/
数据库在手机上的路径

/data/data/包名/databases/

APK重打包
Android Studio -> Build -> Generate signed Bundle/APK 可以生成证书.
apktool d app-release.apk -o outdir_rel  解包apk.
修改smali逻辑......
apktool b outdir_rel  重打包后apk在outdir_rel/dist/目录下面
jarsigner -verbose -keystore xxx.jks(证书) -signedjar xxx.apk(签名后的apk名字) xxx.apk(需要签名的apk) xxx(keystore别名)

签名

https://mp.weixin.qq.com/s/xlgtU4xqoMqv2oXCMko7yQ

为什么用了久置的证书签名安装失败, 新生成的证书就可以呢??可能信息没填完整.

Jeb有内置工具可以修改生成debuggable:true的apk

jeb_wincon.bat -c --makeapkdebug -- file.apk
生成的apk需要重签名
apksigner.bat sign -ks SOME_KEYSTORE.JKS file_debuggable.apk
将dex反编译为smali

baksmali 的使用
下载 https://bitbucket.org/JesusFreke/smali/downloads/

java -jar /usr/local/bin/baksmali-2.5.2.jar d Main.dex

Android Studio SDK的dexdump

dexdump -d Main.dex
查看so文件是32/64位
file xxx.so
或者
readelf -h xxx.so

so和ida的位数不一致就无法使用F5生成伪代码。

查看APK是32/64位
ARM 32位对应的是armv7架构、armv6架构、armv5架构
ARM 64位是armv8架构

常用的abi:
armeabi: armv5架构和armv6架构 (32位)
armeabi-v7a:armv7架构 (32位)
armeabi-v8a:armv8架构 (64位)
x86:x86架构 (32位)
x86_64:x86_64架构 (64位)
查看系统架构
# adb shell getprop ro.product.cpu.abi    
arm64-v8a

查看手机支持的全部架构
# adb shell getprop ro.product.cpu.abilist
arm64-v8a,armeabi-v7a,armeabi

查看手机架构
# adb shell uname -a
Linux localhost 3.18.70-g91a2acf #1 SMP PREEMPT Fri May 11 01:06:35 UTC 2018 aarch64

aarch64架构的so文件存储在lib/arm64-v8a目录下.
一些apk只有arm架构的so文件, 无法运行在x86/64架构计算机中的模拟器上.
IDA Pro动态调试
启动android_server
adb forward tcp:23946 tcp:23946
启动APP
IDA Attach
ndk clang编译c文件 64位可执行文件
$ANDROID_HOME/ndk/21.4.7075529/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang -target aarch64-linux-android21 md5.c -o md5aarch64

预处理
$ANDROID_HOME/ndk/21.4.7075529/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang -target arm-linux-android21 -E md5.c -o md5.i
编译
$ANDROID_HOME/ndk/21.4.7075529/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang -target arm-linux-android21 -S md5.i -o md5.s
汇编
$ANDROID_HOME/ndk/21.4.7075529/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang -target arm-linux-android21 -c md5.s -o md5.o
链接 (链接生成的文件才是可执行文件)
$ANDROID_HOME/ndk/21.4.7075529/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang -target arm-linux-android21 md5.o -o md5

汇编并链接
$ANDROID_HOME/ndk/21.4.7075529/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang -target armv7a-linux-android21 hello.s -o hello

查看段
$ANDROID_HOME/ndk/21.4.7075529/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-readelf --sections md5
查看符号(符号==函数名?)
$ANDROID_HOME/ndk/21.4.7075529/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-nm md5$ANDROID_HOME/ndk/21.4.7075529/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-nm md5

objdump -T xxx.so 查看动态符号
objdump -t xxx.so 查看所有符号

GDB调试

gdb和gdbserver可以在编译的系统源码里找,也可以在android studio的ndk路径下找~/Library/Android/sdk/ndk/21.4.7075529/prebuilt

添加调试符号
编辑build.gradle(:app), android里添加
packagingOptions{
    doNotStrip "*/armeabi/*.so"
    doNotStrip "*/armeabi-v7a/*.so"
    doNotStrip "*/x86/*.so"
}

gdbserver启动64还是32取决于app进程是64还是32位,
可以用object查看,或者查看app进程的父进程(ppid)是zygote还是zygote64

(PC)app进入debug页面
adb shell am start -D -n com.roysue.easyso1/.MainActivity
(PC)查看app进程
adb shell ps -e | grep -i roysue
(手机)手机gdb-server附加到对应进程,端口默认23946
./gdbserver 0.0.0.0:23946 --attach 5718
(PC)运行gdb进入gdb console
~/Documents/20210120/gdb/darwin-x86/bin/gdb
(gdb)连接手机
target remote 172.16.91.172:23946
(gdb)运行c
c
(PC)恢复App运行
/Applications/Android\ Studio.app/Contents/jre/Contents/Home/bin/jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700

直接运行app
查看进程是32/64和进程id启动gdbserver
/data/local/tmp/prebuilt/android-arm/gdbserver/gdbserver 0.0.0.0:23946 --attach 15631
hyper里启动gdb
(gdb) target remote 192.168.1.104:23946
继续程序的运行
(gdb) c

gdb命令
info shared 查看系统库(无调试信息)
c 运行到下个断点

查看so方法

在这里插入图片描述

逆向 笔记_第4张图片
nm -s libroysue.so | grep method (kali)
在这里插入图片描述

查看进程是否被trace

cat /proc/15631/status逆向 笔记_第5张图片
frida注入器只有在注入so的阶段需要ptrace,注入完后即detach,所以TracerPid为0。
frida注入后可以再使用gdbserver,反过来则不行。

为什么android studio动态调试微信trackerpid为0呢?

hyper + gdb + peda

(手机)
/data/local/tmp/prebuilt/android-arm/gdbserver/gdbserver 0.0.0.0:23946 ./hello
(hyper)
gdb
target remote 192.168.1.102:23946
b main
c
disassemble main

在这里插入图片描述
最简单的反编译器 objdump
在这里插入图片描述
“基地址” + “偏移地址”
在这里插入图片描述

因为三级流水线的关系,b main会断点在:逆向 笔记_第6张图片
用算出来的地址b *0xaaaaa3d4则可以断在:
逆向 笔记_第7张图片

push {fp, lr}  # 保存现场,讲fp(r11)和lr(r14)寄存器值入栈

info register 查看寄存器
ni 步过


so

Java层是unicode编码,C是ascii编码

Parallerls Desktop WIN 11使用IDA

使用Host-Only网络,确保虚拟机不联网
adb forward only bind localhost

adb forward tcp:23947 tcp:23946
nohup socat tcp:localhost:23947 tcp-listen:23946 > /dev/null 2>&1 &

ida查看基址

逆向 笔记_第8张图片

查看Intent

adb logcat | fgrep -i intent

在Android中使用vi等linux命令

在Android中使用vi等linux命令
https://blog.csdn.net/cfy137000/article/details/115160014

cp /data/local/tmp/busybox-armv8l /system/xbin/busybox;chmod 755 /system/xbin/busybox;/system/xbin/busybox --install /system/xbin/

so函数批量hook

一个IDA小脚本,获取SO代码段中所有函数的偏移地址,再使用frida-trace 批量trace so函数的调用。
https://github.com/Pr0214/trace_natives

你可能感兴趣的:(逆向,逆向)