├── .gitignore ├── Android ├── A01 │ ├── .DS_Store │ ├── README.md │ └── pic │ │ ├── 01.a.png │ │ ├── 01.b.png │ │ ├── 01.c.png │ │ ├── 01.d.png │ │ ├── 01.e.png │ │ ├── 02.a.webp │ │ └── 02.b.png ├── A02 │ └── README.md ├── A03 │ ├── .DS_Store │ ├── README.md │ └── pic │ │ ├── 01.a.png │ │ └── 02.a.png ├── A04 │ ├── README.md │ ├── docs │ │ └── R1_lesson 1-2.pptx │ └── pic │ │ ├── 01.a.png │ │ ├── 01.b.png │ │ └── 02.a.png ├── A05 │ ├── README.md │ └── pic │ │ ├── 1607018-8564eca6ecbee50d.webp │ │ ├── CBC.png │ │ ├── CFB.png │ │ ├── ECB.png │ │ └── OFB.png ├── A06 │ ├── README.md │ └── pic │ │ ├── 1.png │ │ ├── 10.png │ │ ├── 11.png │ │ ├── 12.png │ │ ├── 13.png │ │ ├── 14.png │ │ ├── 15.png │ │ ├── 16.png │ │ ├── 17.png │ │ ├── 18.png │ │ ├── 19.png │ │ ├── 2.png │ │ ├── 20.png │ │ ├── 21.png │ │ ├── 3.png │ │ ├── 4.png │ │ ├── 5.png │ │ ├── 6.png │ │ ├── 7.png │ │ ├── 8.png │ │ └── 9.png ├── B01 │ ├── .DS_Store │ ├── README.md │ └── pic │ │ ├── 01.a.png │ │ ├── 02.a.png │ │ ├── 03.a.png │ │ └── 04.a.png ├── B02 │ ├── .DS_Store │ ├── README.md │ └── pic │ │ ├── 01.a.png │ │ └── 02.a.png ├── B03 │ ├── .DS_Store │ ├── README.md │ └── pic │ │ ├── .DS_Store │ │ ├── 01.a.png │ │ ├── 02.a.png │ │ ├── 03.a.png │ │ ├── 04.a.png │ │ ├── 05.a.png │ │ └── 06.a.png ├── B04 │ ├── README.md │ └── pic │ │ ├── 01.a.png │ │ ├── 02.a.png │ │ ├── 03.a.png │ │ ├── 04.a.png │ │ ├── 05.a.png │ │ └── 06.a.png ├── C01 │ └── README.md ├── C02 │ ├── README.md │ └── pic │ │ ├── 01.png │ │ └── 02.png └── C03 │ ├── README.md │ └── pic │ ├── 01.png │ ├── 02.png │ ├── 03.png │ └── 04.png ├── FRIDA ├── A01 │ ├── README.md │ └── pic │ │ ├── 01.a.png │ │ ├── 02.a.png │ │ ├── 03.a.png │ │ ├── 04.a.png │ │ └── planet.jpeg ├── A02 │ ├── README.md │ └── pic │ │ └── 01.a.png ├── A03 │ └── README.md ├── B01 │ ├── README.md │ ├── pic │ │ ├── 01.a.png │ │ ├── 01.b.png │ │ ├── 01.c.png │ │ ├── 01.d.png │ │ ├── 01.e.png │ │ ├── 01.f.png │ │ ├── 01.g.png │ │ └── 01.h.png │ └── raptor_frida_android_trace_fixed.js ├── B02 │ ├── README.md │ └── pic │ │ ├── 01.a.png │ │ ├── 02.a.png │ │ └── 03.a.png ├── B03 │ └── README.md ├── B04 │ ├── .DS_Store │ ├── README.md │ └── pic │ │ ├── 01.png │ │ ├── 02.png │ │ └── 03.png └── B05 │ ├── README.md │ ├── check.txt │ ├── jni.h │ ├── pic │ ├── 01.a.png │ ├── 02.a.png │ ├── 03.a.png │ ├── 04.a.png │ ├── 05.a.png │ ├── 06.a.png │ ├── 07.a.png │ ├── 08.a.png │ ├── 09.a.png │ └── 10.a.png │ └── sub_B90.txt ├── README.md └── Tool ├── IDA ├── A01 │ ├── README.md │ ├── pic │ │ ├── 01.a.png │ │ ├── 01.b.png │ │ ├── 01.c.png │ │ ├── 01.d.png │ │ ├── 01.e.png │ │ ├── 02.a.png │ │ ├── 02.b.png │ │ ├── 02.c.png │ │ ├── 03.a.png │ │ ├── 03.b.png │ │ ├── 03.c.png │ │ ├── 03.d.png │ │ ├── 03.e.png │ │ ├── 03.f.png │ │ ├── 04.a.png │ │ ├── 04.b.png │ │ ├── 04.c.png │ │ ├── 04.d.png │ │ ├── 04.e.png │ │ ├── 04.f.png │ │ ├── 04.g.png │ │ ├── 04.h.png │ │ └── 04.i.png │ └── 内容 │ │ ├── 代码和使用到的文件 │ │ ├── main.c │ │ ├── md5_algorithm.py │ │ └── openssl.h │ │ ├── 样本 │ │ ├── 1.so │ │ ├── 2.so │ │ ├── 3.so │ │ ├── libcrypto.so │ │ ├── libkeyinfo.so │ │ ├── libmtguard.so │ │ ├── libmwnative-sign.so │ │ └── libnative-lib.so │ │ └── 资料 │ │ ├── 08960303.pdf │ │ ├── Automated_Identification_of_Cryptographic_Primitiv.pdf │ │ ├── Automatic Detection of Cryptographic Algorithms.pdf │ │ ├── Cryptographic Algorithms Analysis Technology Research Based on Functions Signature Recognition.pdf │ │ ├── Detection and Analysis of Cryptographic Data.pdf │ │ ├── HES-2012-jcalvet-CryptoFunctionIdentification.pdf │ │ ├── Pinpointing Insecure Cryptographic Keys from.pdf │ │ ├── ReFormat Automatic Reverse Engineering of.pdf │ │ ├── openssl编程.pdf │ │ ├── polyglot_ccs07_av.pdf │ │ └── 二进制程序中加解密函数的定位-焦龙龙-2018-06-17-19_00_00.pdf └── A02 │ ├── README.md │ └── pic │ ├── 01.a.png │ ├── 01.b.png │ └── 01.c.png ├── Unidbg ├── A01 │ ├── README.md │ └── pic │ │ └── 01.png ├── A02 │ ├── README.md │ └── pic │ │ ├── 01.png │ │ ├── 02.png │ │ ├── 03.png │ │ ├── 04.png │ │ ├── 05.png │ │ ├── 06.png │ │ ├── 07.png │ │ ├── 08.png │ │ ├── 09.png │ │ ├── 10.png │ │ └── planet.jpeg └── A03 │ ├── README.md │ └── pic │ ├── 01.png │ ├── 02.png │ ├── 03.png │ ├── 04.png │ ├── 05.png │ ├── 06.png │ ├── 07.png │ ├── 08.png │ ├── 09.png │ └── 10.png └── XPOSED └── A01 ├── README.md └── pic ├── 01.a.png └── 02.a.png /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .DS_Store -------------------------------------------------------------------------------- /Android/A01/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A01/.DS_Store -------------------------------------------------------------------------------- /Android/A01/README.md: -------------------------------------------------------------------------------- 1 | ## 1.1 **JNI介绍** 2 | 3 | 定义: JNI,全称为Java Native Interface, 即Java本地接口, JNI是Java调用Native 语言的一种特性。`通过JNI可以使得Java与C/C++机型交互`。即可以在Java代码中调用C/C++等语言的代码或者在C/C++代码中调用Java代码, `由于JNI是JVM规范的一部分,因此可以将我们写的JNI的程序在任何实现了JNI规范的Java虚拟机中运行`, 同时这个特性使我们可以复用以前用C/C++写的大量代码JNI是一种在Java虚拟机机制下的执行代码的标准机制,`相当于java和c、c++中间的桥梁,JNI 大于NDK`, 4 | 5 | 6 | 7 | ## 1.2 **NDK介绍** 8 | 9 | 定义: `Native Development Kit`, 是 `Android`的一个工具开发包, NDK是属于 `Android` 的, 与`Java`并无直接关系,没有NDK就无法编译C++的代码, native层也是可以抓包的, 比如视频电话, NDK原生代码不需要在java虚拟机运行, 而是直接在`cpu`上运行。 10 | 11 | 作用: 快速开发`C`、 `C++`的动态库, 并自动将`so`和应用一起打包成 `APK`, 即可通过 `NDK`在 `Android`中 使用 `JNI`与本地代码(如C、C++)交互。 12 | 13 | 应用场景: 在Android的场景下 使用JNI。 14 | 15 | ``` 16 | 优点: 17 | 1、重复使用现在库,或者提供其自己的库重复使用 18 | 19 | 2、在某些情况下提性能,特别是像游戏这种计算密集型应用 20 | 21 | 3、使用第三方库,现在许多第三方库都是由C/C++库编写的,比如Ffmpeg这样库。 22 | 23 | 4、不依赖于Dalvik Java虚拟机的设计 24 | 25 | 5、代码的保护。由于APK的Java层代码很容易被反编译,而C/C++库反编译难度大。 26 | 27 | 缺点: 28 | 29 | 1、由于和java交互比较繁琐,开发难度较大。 30 | 31 | 2、容易造成内存泄漏,c++和java是两种不同的语言。 32 | ``` 33 | 34 | 35 | 36 | ## 1.3 静态注册 37 | 38 | 打开Android studio文件,创建项目,选c、c++,build编译,打开`build/outputs/apk/debug`下,会有编译好的apk文件,解压进入lib,就会看到so文件。 39 | 40 | ##### java source code view: 41 | 42 | ```java 43 | 目录:src/main/java/com/noguess/demoso1/MainActivity.java 44 | public class MainActivity extends AppCompatActivity { 45 | // Used to load the 'native-lib' library on application startup. 46 | // libnative-lib.so 47 | static { 48 | System.loadLibrary("native-lib"); 49 | } 50 | @Override 51 | protected void onCreate(Bundle savedInstanceState) { 52 | super.onCreate(savedInstanceState); 53 | setContentView(R.layout.activity_main); 54 | // Example of a call to a native method 55 | TextView tv = findViewById(R.id.sample_text); 56 | tv.setText(stringFromJNI()); 57 | // 调用动态方法 58 | Log.i("r0add", String.valueOf(this.myfirstjni())); 59 | // 调用静态方法 60 | Log.i("r0add", MainActivity.myfirstjniJNI("from JAVA")); 61 | } 62 | /** 63 | * A native method that is implemented by the 'native-lib' native library, 64 | * which is packaged with this application. 65 | * native 关键字,函数返回类型为String 66 | */ 67 | public native String stringFromJNI(); 68 | // public static native String stringFromJNI(); 69 | public native int myfirstjni(); 70 | } 71 | ``` 72 | 73 | 74 | 75 | ##### native source code view: 76 | 77 | ```c++ 78 | 目录:src/main/cpp/native-lib.cpp 79 | 点击java层stringFromJNI也可以跳进去。 80 | #include 81 | #include 82 | int r0add(int x, int y){ 83 | return x + y; 84 | } 85 | extern "C" JNIEXPORT jstring JNICALL 86 | Java_com_noguess_demoso1_MainActivity_stringFromJNI( 87 | # 两个必要参数,最少不会少于两个。 88 | JNIEnv* env, 89 | jobject /* this */) { 90 | std::string hello = "Hello from C++"; 91 | # NewStringUTF:JNI API 92 | // NewStringUTF有两个参数,第一个默认为env 93 | return env->NewStringUTF(hello.c_str()); 94 | } 95 | extern "C" JNIEXPORT jint JNICALL 96 | Java_com_noguess_demoso1_MainActivity_myfirstjni( 97 | JNIEnv* env, 98 | jobject /* this */) { 99 | return r0add(10 ,20); 100 | } 101 | ``` 102 | 103 | `stringFromJNI` 加了一个**native**描述符,表示是一个原生函数,`MainActivity`是类名,`com_noguess_demoso1`是包名,`Java_com_noguess_demoso1_MainActivity_stringFromJNI`是对应的C函数名,那么这个规则就很显而易见了,将包名的.替换成_(因为.不能用于函数命名),然后`Java_PackName_CLassName_MethodName`。**运行时,JNI就会依赖此规则来对函数进行绑定**。 104 | 105 | 注释: 106 | 107 | 1. jstring JNICALL 指返回的类型为string。 108 | 109 | 2. JNIEXPORT:表明此函数为导出函数,如果不加,则java调用不了。 110 | 111 | ![](pic/01.b.png) 112 | 113 | 114 | 115 | 116 | 117 | 3. Java_com_noguess_demoso1_MainActivity_stringFromJNI:`包名_类名_函数名`,静态固定格式。 118 | 119 | 4. JNIEnv* env:一个接口指针 120 | 121 | 5. `jobject /* this */ `:在本地方法中声明的对象引用,定义为当前MainActivity的一个实例。如果java层代码加一个static变成静态方法,此处就要改成jclass, 个人理解 jobject为对象调用动态方法,jclass:为类调用静态方法。 122 | 123 | 6. extern "c":如果前面声明了,表示使用c的形式编译。ida反编译后查看此函数,就不会使用`name mangling`。 124 | 125 | > 名字不一样,**c++函数要支持函数名重载**,就会用name mangling来进行混淆,可以使用c++filt -n 来进行还原原函数名。 126 | > 127 | > name mangling 还原相关文档:https://github.com/nico/demumble 128 | 129 | ![](pic/01.c.png) 130 | 131 | 1. myfirstjni 加了extern “c”, 函数名就不会变。 132 | 133 | ![](pic/01.d.png) 134 | 135 | 2. r0add没有加, 函数名变化。 136 | 137 | ![](pic/01.e.png) 138 | 139 | ​ 140 | 141 | 7. jint 指的是此函数返回的数据类型为int类型, native函数返回的是什么数据类型,java层也要写对应的数据类型。 142 | 143 | JNI数据类型和java数据类型关系如下: 144 | 145 | 146 | 147 | 8. 开发一个简单的JNI -> HELLO WORD 148 | 149 | ##### java source code view: 150 | 151 | ```java 152 | package com.noguess.demoso1; 153 | import androidx.appcompat.app.AppCompatActivity; 154 | import android.os.Bundle; 155 | import android.util.Log; 156 | import android.widget.TextView; 157 | 158 | import java.lang.reflect.Field; 159 | 160 | public class MainActivity extends AppCompatActivity { 161 | // Used to load the 'native-lib' library on application startup. 162 | static { 163 | System.loadLibrary("native-lib"); 164 | } 165 | 166 | @Override 167 | protected void onCreate(Bundle savedInstanceState) { 168 | super.onCreate(savedInstanceState); 169 | setContentView(R.layout.activity_main); 170 | 171 | // Example of a call to a native method 172 | TextView tv = findViewById(R.id.sample_text); 173 | tv.setText(stringFromJNI()); 174 | // 调用动态方法 175 | Log.i("r0add", String.valueOf(this.myfirstjni())); 176 | // 调用静态方法 177 | Log.i("r0add", MainActivity.myfirstjniJNI("from JAVA")); 178 | } 179 | 180 | /** 181 | * A native method that is implemented by the 'native-lib' native library, 182 | * which is packaged with this application. 183 | */ 184 | public native String stringFromJNI(); 185 | // 静态方法 186 | public static native String myfirstjniJNI(String context); 187 | public native int myfirstjni(); 188 | } 189 | ``` 190 | 191 | ##### Native source code view: 192 | 193 | ```c++ 194 | extern "C" JNIEXPORT jstring JNICALL 195 | // 固定格式 196 | Java_com_noguess_demoso1_MainActivity_myfirstjniJNI( 197 | // 固定参数 198 | JNIEnv *env, 199 | // 静态 -> jclass, 动态 -> jobject 200 | jclass clazz, 201 | // 参数 202 | jstring context) { 203 | // c++的写法 204 | const char* a = env->GetStringUTFChars(context, nullptr); 205 | 206 | int a_size = env->GetStringUTFLength(context); 207 | if(a!=0){ 208 | // LOGI('now a is %s', a); 209 | // LOGI('new context is %s', context); 210 | } 211 | // 不用的对象释放掉 212 | env->ReleaseStringUTFChars(context, a); 213 | // 创建一个utf-8字符串 214 | jstring result = env->NewStringUTF("Hello I`am from myfirstjniJNI"); 215 | return result; 216 | ``` 217 | 218 | 219 | 220 | ## 1.4 动态注册 221 | 222 | 如今许多开发者都出于**安全性考虑**或其他需求,不愿使用函数名规则绑定,而是自己动态注册来绑定native函数。方法也很简单,只需调用`RegisterNatives`函数即可。其申明如下: 223 | 224 | ```c++ 225 | jint RegisterNatives(jclass clazz, const JNINativeMethod* methods,jint nMethods) 226 | ``` 227 | 228 | `clazz` 就是native函数所在的类,可通过`FindClass`获取(将.换成/);`methods`是一个数组,其中包含注册信息。 229 | 230 | ##### java source code view: 231 | 232 | ```java 233 | public static native String stringFromJNI2(); 234 | ``` 235 | 236 | ##### Native source code view: 237 | 238 | ```c++ 239 | // 动态注册: so 240 | JNIEXPORT jstring JNICALL stringFromJNI2(JNIEnv* env, jclass clazz) { 241 | std::string hello = "Hello from C++ stringFromJNI2"; 242 | return env->NewStringUTF(hello.c_str()); 243 | } 244 | 245 | JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) 246 | { 247 | JNIEnv * env; 248 | // 从java虚拟机中获取java env 249 | vm->GetEnv((void**)&env,JNI_VERSION_1_6); 250 | // 注册信息 251 | JNINativeMethod methods[] = { 252 | // 签名()Ljava/lang/String; 括号里是参数, 返回值是一个jstring 253 | // name:stringFromJNI2 是与java层 public static native String stringFromJNI2();对应的 254 | {"stringFromJNI2","()Ljava/lang/String;",(void*)stringFromJNI2}, 255 | }; 256 | // FindClass寻找类 257 | // RegisterNatives为env的函数,代表此函数可以hook。 258 | // RegisterNatives参数详解:FindClass寻找类 methods:方法数组 1:方法个数 259 | env->RegisterNatives(env->FindClass("com/example/demoso1/MainActivity"),methods,1); 260 | return JNI_VERSION_1_6; 261 | } 262 | ``` 263 | 264 | ##### JNI ONLOAD 265 | 266 | 如果代码中已经实现了,那么ida中就可以搜索到。JNI ONLOAD是一个回调,加载一个so时会自动执行。 267 | 268 | ![](pic/02.b.png) 269 | 270 | ida中代码: 271 | 272 | ```c++ 273 | { 274 | unsigned __int64 v1; // x8 275 | unsigned __int64 v2; // ST20_8 276 | void *v3; // ST10_8 277 | __int64 v4; // x0 278 | __int64 result; // x0 279 | void *v6; // [xsp+38h] [xbp-28h] 280 | __int128 v7; // [xsp+40h] [xbp-20h] 281 | __int64 (__fastcall *v8)(int, int, int, int, int, int, int, int, int, int, __int64); // [xsp+50h] [xbp-10h] 282 | __int64 v9; // [xsp+58h] [xbp-8h] 283 | 284 | v1 = _ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)); 285 | v9 = *(_QWORD *)(v1 + 40); 286 | v2 = v1; 287 | // 源码:vm->GetEnv((void**)&env,JNI_VERSION_1_6),所以v6就是env,可以按y键重命名方便观看。 288 | _JavaVM::GetEnv(a1, &v6, 65542); 289 | // v8就是动态注册的函数名 290 | v8 = stringFromJNI2; 291 | v7 = off_32CB8; 292 | v3 = v6; 293 | v4 = _JNIEnv::FindClass((_JNIEnv *)v6, "com/example/demoso1/MainActivity"); 294 | result = _JNIEnv::RegisterNatives(v3, v4, &v7, 1LL); 295 | if ( *(_QWORD *)(v2 + 40) == v9 ) 296 | result = 65542LL; 297 | return result; 298 | } 299 | ``` 300 | 301 | ## 1.5 参考链接 302 | 303 | > [以上提到的`源码`的地址](https://github.com/heyhu/demoso1) 304 | > 305 | > [Android ABI](https://developer.android.google.cn/ndk/guides/abis) 306 | > 307 | > [NDK与JNI基础](https://www.jianshu.com/p/87ce6f565d37) 308 | > 309 | > [ndk-samples ](https://github.com/android/ndk-samples) 310 | > 311 | > [frida_env.js](https://github.com/frida/frida-java-bridge/blob/master/lib/env.js) 312 | -------------------------------------------------------------------------------- /Android/A01/pic/01.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A01/pic/01.a.png -------------------------------------------------------------------------------- /Android/A01/pic/01.b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A01/pic/01.b.png -------------------------------------------------------------------------------- /Android/A01/pic/01.c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A01/pic/01.c.png -------------------------------------------------------------------------------- /Android/A01/pic/01.d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A01/pic/01.d.png -------------------------------------------------------------------------------- /Android/A01/pic/01.e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A01/pic/01.e.png -------------------------------------------------------------------------------- /Android/A01/pic/02.a.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A01/pic/02.a.webp -------------------------------------------------------------------------------- /Android/A01/pic/02.b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A01/pic/02.b.png -------------------------------------------------------------------------------- /Android/A03/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A03/.DS_Store -------------------------------------------------------------------------------- /Android/A03/README.md: -------------------------------------------------------------------------------- 1 | ## 1.1 基础开发 2 | 3 | ### 1.1.1 创建一个新的c文件 4 | 5 | 1. 在 `app/src/main/cpp`新建一个C/C++ Source File,type选择 `.c `。填入代码,点击Sync Now,同步代码。 6 | 7 | ```c 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define TAG "heyTag" 17 | 18 | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG,__VA_ARGS__) 19 | 20 | /* This is a trivial JNI example where we use a native method 21 | * to return a new VM String. See the corresponding Java source 22 | * file located at: 23 | * 24 | * hello-jni/app/src/main/java/com/example/hellojni/HelloJni.java 25 | */ 26 | 27 | JNIEXPORT jstring JNICALL 28 | Java_com_heyhu_openso_MainActivity_stringFromJNI(JNIEnv *env, jobject thiz) { 29 | #if defined(__arm__) 30 | #if defined(__ARM_ARCH_7A__) 31 | #if defined(__ARM_NEON__) 32 | #if defined(__ARM_PCS_VFP) 33 | #define ABI "armeabi-v7a/NEON (hard-float)" 34 | #else 35 | #define ABI "armeabi-v7a/NEON" 36 | #endif 37 | #else 38 | #if defined(__ARM_PCS_VFP) 39 | #define ABI "armeabi-v7a (hard-float)" 40 | #else 41 | #define ABI "armeabi-v7a" 42 | #endif 43 | #endif 44 | #else 45 | #define ABI "armeabi" 46 | #endif 47 | #elif defined(__i386__) 48 | #define ABI "x86" 49 | #elif defined(__x86_64__) 50 | #define ABI "x86_64" 51 | #elif defined(__mips64) /* mips64el-* toolchain defines __mips__ too */ 52 | #define ABI "mips64" 53 | #elif defined(__mips__) 54 | #define ABI "mips" 55 | #elif defined(__aarch64__) 56 | #define ABI "arm64-v8a" 57 | #else 58 | #define ABI "unknown" 59 | #endif 60 | 61 | return (*env)->NewStringUTF(env, "Hello from JNI ! Compiled with ABI " ABI "."); 62 | } 63 | 64 | ``` 65 | 66 | 2. 在CmakeLists.txt 声明新建的 `heyhu.c`文件。 67 | 68 | ```txt 69 | add_library( # Sets the name of the library. 70 | heyhu 71 | 72 | # Sets the library as a shared library. 73 | # 这里共享, 别的app就可以load此so文件 74 | SHARED 75 | 76 | # Provides a relative path to your source file(s). 77 | heyhu.c ) 78 | 79 | 80 | target_link_libraries( # Specifies the target library. 81 | heyhu 82 | 83 | # Links the target library to the log library 84 | # included in the NDK. 85 | ${log-lib} ) 86 | ``` 87 | 88 | 3. 在 Java文件中声明加载的文件, 运行在手机上就可以看到效果了。 89 | 90 | ```java 91 | static { 92 | System.loadLibrary("heyhu"); 93 | } 94 | ``` 95 | 96 | 97 | 98 | ### 1.1.2 C语言md5[交叉]编译 99 | 100 | 编译本地版 101 | 102 | 1. [编写md5的c代码到本地](https://github.com/pod32g/MD5), 在github中找一个即可。 103 | 2. 到对应目录下执行gcc -o md5 md5.c`命令进行编译。 104 | 3. `./md5 heyhu` 得到`heyhu`的md5值。 105 | 106 | 将NDK与其他构建系统配合使用 107 | 108 | 1. `/Android/sdk/ndk/21.0.6113669/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang -target aarch64-linux-android21 md5.clang`,会生成一个`a.out`可执行文件。注意c++ 需要使用 `clang ++`。 109 | 2. 因为我们选择的ABI位arm64-v8a,需要讲此文件push到手机上进行执行。对应关系详见[文档](https://developer.android.google.cn/ndk/guides/other_build_systems)。 110 | 111 | 移植到代码中: [heyhu.c](https://github.com/heyhu/openso/blob/master/app/src/main/cpp/heyhu.c) 112 | 113 | Tips `如果安装后结果不对,可以删除/app/build/outputs/apk下的文件,修改成32位ABI即可` 114 | 115 | 116 | 117 | ### 1.1.3 指定32位 118 | 119 | ```java 120 | android { 121 | compileSdkVersion 30 122 | buildToolsVersion "30.0.2" 123 | 124 | defaultConfig { 125 | applicationId "com.heyhu.openso" 126 | minSdkVersion 16 127 | targetSdkVersion 30 128 | versionCode 1 129 | versionName "1.0" 130 | 131 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 132 | externalNativeBuild { 133 | cmake { 134 | cppFlags "" 135 | } 136 | // 现在基本32位 137 | ndk { 138 | abiFilters 'armeabi-v7a' 139 | } 140 | 141 | } 142 | } 143 | ``` 144 | 145 | 146 | 147 | ## 1.2 llvm组件lldb 148 | 149 | llvm可以进行汇编、反汇编,机器码反汇编成16进制、指令集(disassemble)。llvm可以把C\C++代码编译成一个SO文件。 150 | 151 | 调试第三方App满足以下任意一种方式即可,推荐第二种方式: 152 | 153 | 1. app以debug模式、apk包中debuggable==true(得重打包、或者xposed/frida去hook) 154 | 2. 手机是aosp系统,编译成userdebug模式(n5x、sailfish) 155 | 156 | 157 | 158 | ### 1.2.1 Android Studio Debug调试原理 159 | 160 | bebug的时候 会把llvm的组件lldb中的start_lldb_server.sh push到手机的`/data/local/tmp/`中,调试的时候会启动lldb服务。 161 | 162 | 如果之前使用Android Studio Debug过,它会自动帮我们push。 163 | 164 | ![](/Android/A03/pic/01.a.png) 165 | 166 | 如果没有需要手动把文件push到手机中,其路径为`/Users/zhaoshouxin/Library/Android/sdk/ndk/21.0.6113669/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/9.0.8/lib/linux/aarch64或者arm以及x86_64`。aarch64位64位、arm为32位,以app进程为基准,不可混用。push完成后运行`./lldb-server`看是否可用。 167 | 168 | lldb路径:`/Android/sdk/ndk/21.0.6113669/toolchains/llvm/prebuilt/darwin-x86_64/bin/lldb` 与clang在同一目录下,可以把目录设置为环境变量。 169 | 170 | 在Android Studio bebug模式下,旁边也有lldb切换卡,也可以操作lldb。 171 | 172 | 173 | 174 | ## 1.2.2 lldb命令 175 | 176 | > 手机下启动lldb服务 ./lldb-server platform --listen "*:10086" --server 177 | 178 | 首先你需要在你的linux系统上安装lldb,然后执行lldb。进入后执行以下命令 179 | 180 | ``` 181 | platform select remote-android 182 | 183 | #ENU7N16709000458 是adb devices显示的设备名称 184 | platform connect connect://ENU7N16709000458:10086 185 | attach -p 30827 186 | ``` 187 | 188 | 详细文章[入口](https://my.oschina.net/u/4263893/blog/4349408)。 189 | 190 | 191 | 192 | ## 1.3 Frida Instruction 193 | 194 | Capstone/Keystone(反)汇编器 195 | 196 | 作用:动态反汇编。原理内置Capstone 197 | 198 | ```javascript 199 | function dis(address, number) { 200 | for (var i = 0; i < number; i++) { 201 | var ins = Instruction.parse(address); 202 | console.log("address:" + address + "--dis:" + ins.toString()); 203 | address = ins.next; 204 | } 205 | } 206 | setImmediate(function(){ 207 | var stringFromJniaddr = Module.findExportByName("libroysue.so","Java_com_roysue_easyso1_MainActivity_stringFromJNI") 208 | dis(stringFromJniaddr,10); 209 | }) 210 | ``` 211 | 212 | 和lldb打印的一样。 213 | 214 | ![](/Android/A03/pic/02.a.png) 215 | 216 | 217 | 218 | ## 1.4 HyperPwn调试入门 219 | 220 | ### 1.4.1 app设置为可调式 221 | 222 | ``` 223 | CMakeLists.txt 最下面添加 224 | 225 | # gdb 调试 226 | SET(CMAKE_BUILD_TYPE "Debug") 227 | SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb") 228 | SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall") 229 | ``` 230 | 231 | ``` 232 | app下的build.gradle中android添加 233 | 234 | packagingOptions{ 235 | doNotStrip "*/armeabi/*.so" 236 | doNotStrip "*/armeabi-v7a/*.so" 237 | doNotStrip "*/x86/*.so" 238 | } 239 | ``` 240 | 241 | 编译成功后,so文件会增加100k左右。 242 | 243 | 244 | 245 | ### 1.4.2 环境搭建 246 | 247 | GDB 为C/S的调试架构: 248 | 249 | > 服务端地址为:`Android/sdk/ndk/22.0.7026061/prebuilt/android-arm/gdbserver` 250 | > 251 | > 客户端使用前人编译好的[Pwndocker](https://github.com/skysider/pwndocker) 252 | > 253 | > 进入docker后运行gdb-multiarch,要不然会报错。 254 | 255 | 256 | 257 | ### 1.4.3 调试 258 | 259 | ``` 260 | $ 手机内启动64/32gdbserver: ./gdbserver 0.0.0.0:23946 --attach target_pip 261 | 262 | $ 端口转发: adb forward tcp:23946 tcp:23946 263 | 264 | $ docker内运行客户端gdb-multiarch,进入pwndbg 265 | 266 | $ 连接服务端target remote 手机ip:23946  267 | 268 | $ pwndbg设置架构: set arch arm, set arm fallback-mode thumb  269 | 270 | $ c(运行到下一个断点) r(继续运行) ctrl+c暂停  info share查看所有加载的so   271 | 272 | $ nm -s so_name 查看所有符号 273 | 274 | $ 本地运行: nm -s so_name |grep method 查看 "*method*"方法地址或者使用objection、frida查看 275 | 276 | $ 查看该地址汇编: x/20i base_addr 277 | cat /proc/10700/maps |grep heyhu 基址为:d1241000 278 | d1241000-d1247000 r-xp 00000000 103:13 917882 279 | 280 | $ b *(base_addr)设置断点  info b 查看断点  281 | 282 | $ del 编号 删除断点 283 | 284 | $ 步入:f7 步进:f8 285 | 286 | $ finish 跳出方法   287 | 288 | $ frida主动调用方法和pwndbg同时使用的话需要先启动frida附加(注入器注入之后ptracepid=0)然后再启动gdbserver,在主动调用时候先用pwndbg暂停, 289 | 然后frida主动调用, 然后f8就可以一步一步调试了。 290 | 291 | $ objection查看so基址:memory list modules 292 | 293 | $ memory list exports so_name 查看so的所有符号基址 294 | 295 | $ 下两个断点切换状态 ctrl+shift+pageup 296 | 297 | $ frida和gdb为什么不能一起调试? 298 | 其中一个程序attach目标进程时,TracerPid会被占用,别的进程就附加不上。 299 | cat /proc/10700/status TracerPid: 25096 -> gdb 300 | 301 | $ 为什么frida先附加后,gdb可以进行调试? 302 | 谁进行调试 TracerPid就是谁的进程,frida注入后 TracerPid为0,因为注入器注入后就dettch了,然后就可以用gdb了。 303 | ``` 304 | 305 | 306 | 307 | ### 1.4.4 判断app使用的架构 308 | 309 | ``` 310 | Objection:Process Architecture arm 311 | 312 | 查看目标进程的父进程 313 | root 3316 1 4213072 48928 poll_schedule_timeout 7135b2b518 S zygote64 314 | root 3317 1 1552068 40104 poll_schedule_timeout e72ebc4c S zygote 315 | ``` 316 | 317 | 318 | 319 | ## 1.5 参考链接 320 | 321 | https://developer.android.google.cn/ndk/guides/other_build_systems 322 | 323 | https://my.oschina.net/u/4263893/blog/4349408 324 | 325 | https://blog.csdn.net/wangyiyungw/article/details/81069631 326 | 327 | https://github.com/heyhu/openso 328 | 329 | https://lldb.llvm.org/use/map.html 330 | 331 | --- 332 | 333 | https://github.com/skysider/pwndocker 334 | 335 | https://www.cnblogs.com/zhwer/p/12494317.html 336 | 337 | https://bbs.pediy.com/thread-257344.htm 338 | 339 | https://blog.csdn.net/l460133921/article/details/52931328/ 340 | -------------------------------------------------------------------------------- /Android/A03/pic/01.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A03/pic/01.a.png -------------------------------------------------------------------------------- /Android/A03/pic/02.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A03/pic/02.a.png -------------------------------------------------------------------------------- /Android/A04/README.md: -------------------------------------------------------------------------------- 1 | ## 1.1 MD5 2 | 3 | 输出长度16个字节,或者说32个十六进制数(一个字节两个16进制数),有时候输出16个十六进制数。 4 | 5 | > MD5_Init 初始化 6 | > 7 | > MD5_Update 添加参数,也就是要加密的值 8 | > 9 | > MD5_Final 获取结果 10 | 11 | ### 1.1.1 初始化魔数 12 | 13 | 初始化魔数也叫初始化链接变量或者iv: 14 | 15 | ```c 16 | A = 0x67452301; 17 | B = 0xEFCDAB89; 18 | C = 0x98BADCFE; 19 | D = 0x10325476; 20 | ``` 21 | 22 | ida中样本: 23 | 24 | ```c 25 | _DWORD *__fastcall MD5Init(_DWORD *result) 26 | { 27 | result[5] = 0; 28 | result[4] = 0; 29 | *result = 0x67452301; 30 | result[1] = 0xEFCDAB89; 31 | result[2] = -1732584194; 32 | result[3] = 271733878; 33 | return result; 34 | } 35 | // 按h键还原16进制和源码初始化链接变量比较 36 | ``` 37 | 38 | ### 1.1.2 K表 39 | 40 | ```c 41 | K1 = 0xd76aa478 42 | K2 = 0xe8c7b756 43 | K3 = 0x242070db 44 | ``` 45 | 46 | k表中共`64`个常数,来自sin函数,共64轮运算,每一轮运算使用一个k值,在ida中看前三轮是不是和源码一样就能确定是否魔改了,运算部分查看和源码k表对应一下。 47 | 48 | 因为md5共64轮运算,所以运算过程很长,运算的时候经常会运行一些函数,c源码如下,重复使用FF函数: 49 | 50 | ```c 51 | FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ 52 | FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ 53 | FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ 54 | FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ 55 | FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ 56 | FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ 57 | FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ 58 | FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ 59 | FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ 60 | FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ 61 | FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ 62 | FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ 63 | FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ 64 | FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ 65 | FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ 66 | FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ 67 | ``` 68 | 69 | ida中 md5运算部分,重复执行`__ROR4__`函数: 70 | 71 | ```c 72 | v6 = v3 + __ROR4__((v5 & ~v3 | v4 & v3) + v71 + v2 - 0x28955B88, 25); 73 | v7 = v6 + __ROR4__((v4 & ~v6 | v3 & v6) + v72 + v5 - 0x173848AA, 20); 74 | v8 = v7 + __ROR4__((v3 & ~v7 | v6 & v7) + v73 + v4 + 0x242070DB, 15); 75 | v9 = v8 + __ROR4__((v6 & ~v8 | v7 & v8) + v74 + v3 - 1044525330, 10); 76 | v10 = v9 + __ROR4__((v7 & ~v9 | v8 & v9) + v75 + v6 - 176418897, 25); 77 | v11 = v10 + __ROR4__((v8 & ~v10 | v9 & v10) + v76 + v7 + 1200080426, 20); 78 | ``` 79 | 80 | 发现和源码中不同,假如左边是减号,还需要右键inver sign变成正常的k值,加号的话就不用动。 81 | 82 | ### 1.1.3 拓展 83 | 84 | 1. md5_HALF 85 | 86 | > 正常的md5 截取中间的一部分 87 | 88 | 2. 加盐 md5 89 | 90 | > 传入一个空值,看他的输出,输出与在线md5网站上,比如cmd5碰下运气(彩虹表碰撞) 91 | > 92 | > salt:9位以内往往可以测试出来 93 | 94 | ### 1.1.4 手算md5 95 | 96 | ![](pic/01.b.png) 97 | 98 | ```c 99 | 明文:123456 100 | 对内容进行编码:ASCII, 123456 的hex为 31 32 33 34 35 36 101 | 第一步:附加比特位,使得其比特长度除以512余448 102 | 1. 31 32 33 34 35 36 现在为12个16进制数也就是48比特,需要填充到448比特长 103 | 2. 31的二进制为 0011 0001 那么31 32 33 34 35 36对应的二进制就是 0011 0001 0011 0010 0011 0011 0011 0100 0011 0101 0011 0110 104 | 3. 此时为48比特长,剩余的400用1000000000..0来表示,因为二进制看来很复杂 用16进制来表示,10000000也就是80, 400 / 4 = 100 - 12 = 88, 313234353680......0 105 | 106 | 第二步:附加长度信息 107 | 1. 512-448=64,特意留存的64比特长,用于附加长度信息。3132343536明文信息48比特长,给了64比特长(16个16进制数)大小去记录,所以就是4800000000000000(16个16进制数,前面48为长度,后面14个用0补齐) 108 | 2. 所以最后的明文信息就是128位长 3132333435368000000000000003000000000000000(48转换为16进制也就是30) 109 | 3. 如果明文就是448,也必须填充 110 | 111 | 第三步: 计算 112 | 1.初始化链接变量/IV/初始化魔数 113 | A = 0x67452301; 114 | B = 0xEFCDAB89; 115 | C = 0x98BADCFE; 116 | D = 0x10325476; 117 | 2. 明文分成16块,128 / 16 = 8,因为一共64轮,共4组,每组16次。明文分组然后进行大小端序转化。 118 | m1 = 31323334 34333231 119 | m2 = 35368000 00086353 120 | m3 = 0... 0 121 | m15 = 30000000 30 122 | m16 = 0.... 0 123 | 3. 第一轮的时候由图可得知A的结果是上一轮的D,B的结果是有上一轮的A的值的计算,C的结果是上一轮的B,D的结果是上一轮的C。 124 | 那么此时 A1 = 0x10325476;B1 = 未知。C1 = 0xEFCDAB89; D1 = 0x98BADCFE; 125 | B的计算: 126 | 第一步: A + F(B,C,D) 127 | F为非线性函数 由4个组成 128 | f1 1-16轮用 (x&y)| ((~x) &z) if x then y else z 129 | f2 17-32轮用 if Z then x else y 130 | f3 32-48轮用 131 | f4 49-64轮用 Y ^ (x|(~z)) 132 | 所以f1(b,c,d ) 133 | b = 1101111110011011010101110001001 134 | c = 10011000101110101101110011111110 135 | d = 10000001100100101010001110110 136 | 10011000101110101101110011111110 = 0x98BADCFE 单纯的巧合 137 | 第二步:0x98BADCFE + A = 0x67452301 + 0x98BADCFE = ffffffff 138 | 第三步:ffffffff + m1 = ffffffff + 34333231 = 134333230 139 | 第四步:134333230 + k1 = 134333230 + 0xd76aa478 = 20B9DD6A8 (k表64个32比特 ki = 2的32次方 ✖️ /sin i/ 取整数的16进制) 140 | 第五步:循环左移 141 | 先处理消高位只要后8位 0B9DD6A8 142 | 在循环左移 <<< 第一轮循环左移7位 规定好的 143 | 先转换2进制 0000101 1100111 0111010 1101010 1000(32个比特长) 144 | 1100111 0111010 1101010 1000 0000101 转换为16进制 CEEB5405 145 | 第六步:b1 = CEEB5405 + B = CEEB5405 + 0xEFCDAB89 = 1BEB8FF8E 最后B1的结果为:1BEB8FF8E 146 | 4. 最后一轮: 147 | A63 = B7E871AF 148 | B63 = BF2579C0 149 | C63 = 2E55BB7C 150 | D63 = D296E7E0 151 | f4 = Y ^ (x|(~z)) 152 | A + F(B,C,D) = B7E871AF + 9138C2A3 = 149213452 + m64 = 149213452 + 0 153 | 149213452 + k64 = 149213452 + eb86d391 = 234a807e3 154 | 34a807e3 先转换2进制 155 | 00110100101010000000011111100011 156 | 循环左移21位 157 | 11111100011001101001010100000000 = FC669400 + b = FC669400 + BF2579C0 = 1BB8C0dc0 158 | 舍弃高位 BB8C0dc0 159 | 160 | A64 = D296E7E0 161 | B64 = BB8C0dc0 162 | C64 = BF2579C0 163 | D64 = 2E55BB7C 164 | 165 | 第四步: 得出结果(与原始相加做级联) 166 | 1. 与原始相加舍最高位 167 | a = D296E7E0 + 0x67452301 = 39dc0ae1 168 | b = BB8C0dc0 + 0xEFCDAB89 = ab59b949 169 | c = BF2579C0 + 0x98BADCFE = 57e056be 170 | d = 2E55BB7C + 0x10325476 = 3e880ff2 171 | 2. 做级联,先端序转换 172 | e10adc39 + 49b959ab + be56e057 + f20f883e 173 | 174 | ``` 175 | 176 | 177 | 178 | ## 1.2 SHA1 179 | 180 | 输出长度20个字节,或者说40个十六进制数 181 | 182 | ### 1.2.1 初始化魔数 183 | 184 | 和MD5相比,有五个初始化链接变量,而且前四个链接变量完全相同。 185 | 186 | ```c 187 | A = 0x67452301 188 | B = 0xEFCDAB89 189 | C = 0x98BADCFE 190 | D = 0x10325476 191 | E = 0xC3D2E1F0 192 | ``` 193 | 194 | ### 1.2.2 K表 195 | 196 | 只有四个K值,共80轮运算每20轮左右用同一个K作变换,一般魔改只会魔改常数,不会对k进行修改 197 | 198 | ```c 199 | K1 = 0x5a827999 200 | K2 = 0x6ed9eba1 201 | K3 = 0x8f1bbcdc 202 | K4 = 0xca62c1d6 203 | ``` 204 | 205 | ### 1.2.3 拓展 206 | 207 | sha0是有缺陷的算法,iv以及k都一样,如果测试的结果和sha1不一样,那么就可以用sha0测试下。 208 | 209 | 210 | 211 | ## 1.3 SHA256 212 | 213 | 输出长度为32个字节,或者说64个十六进制数,结果来自iv计算的拼接, 8 * 8 = 64 214 | 215 | ### 1.3.1 初始化魔数 216 | 217 | IV:八个初始化链接变量 218 | 219 | ```c 220 | A = 0x6A09E667; 221 | B = 0xBB67AE85; 222 | C = 0x3C6EF372; 223 | D = 0xA54FF53A; 224 | E = 0x510E527F; 225 | F = 0x9B05688C; 226 | G = 0x1F83D9AB; 227 | H = 0x5BE0CD19; 228 | ``` 229 | 230 | ### 1.3.2 K表 231 | 232 | 有64个K值,每轮1个K值,K值来自素数,使用前4个与ida中伪代码对照即可。 233 | 234 | ```c 235 | K1 = 0x428a2f98 236 | K2 = 0x71374491 237 | K3 = 0xb5c0fbcf 238 | K4 = 0xe9b5dba5 239 | ``` 240 | 241 | 242 | 243 | ## 1.4 SHA512 244 | 245 | 输出长度为64字节,或者说128个十六进制数 246 | 247 | ### 1.4.1 初始化魔数 248 | 249 | 八个初始化链接变量,IDA反编译也时常显示为16个,给拆开了 250 | 251 | ```c 252 | A = 0x6a09e667f3bcc908; // 到67和sha256一样 253 | B = 0xbb67ae8584caa73b; 254 | C = 0x3c6ef372fe94f82b; 255 | D = 0xa54ff53a5f1d36f1; 256 | E = 0x510e527fade682d1; 257 | F = 0x9b05688c2b3e6c1f; 258 | G = 0x1f83d9abfb41bd6b; 259 | H = 0x5be0cd19137e2179; 260 | ``` 261 | 262 | ## 1.4.2 K表 263 | 264 | 有80个K,每一轮一个K,K值来自素数。 265 | 266 | 前半部分与sha256一致,看最后是否有16个k,对照最后一个k值来区分是256还是512。 267 | 268 | ```c 269 | K1 = 0x428a2f98 270 | K2 = 0x71374491 271 | K3 = 0xb5c0fbcf 272 | K4 = 0xe9b5dba5 273 | ``` 274 | 275 | 276 | 277 | ## 1.5 HMAC-xxx系列 278 | 279 | HMAC-MD5、HMAC-SHA1 280 | 281 | 防止彩虹表碰撞,加盐 + 双重哈希方案 282 | 283 | ### 1.5.1 特征 284 | 285 | 两次加盐,两次MD5、两次异或(主要是看异或的值) 286 | 287 | 16进制: 288 | 289 | > k_ipad[i] ^= 0x36; 290 | > k_opad[i] ^= 0x5c; 291 | 292 | 10进制: 293 | 294 | > v14[i] ^= 54u; 295 | > v13[i] ^= 92u; 296 | 297 | ida中 298 | 299 | ```c 300 | if ( a4 >= 65 ) 301 | { 302 | j_MD5Init(&v11); 303 | j_MD5Update((int)&v11, (int)v8, v7); 304 | ((void (*)(void))j_MD5Final)(); 305 | v8 = &v12; 306 | v7 = 16; 307 | } 308 | _aeabi_memclr(v14, 65); 309 | _aeabi_memclr(v13, 65); 310 | _aeabi_memmove(v14, v8, v7); 311 | _aeabi_memmove(v13, v8, v7); 312 | for ( i = 0; i <= 63; ++i ) 313 | { 314 | v14[i] ^= 0x36u; //异或值 315 | v13[i] ^= 0x5Cu; //异或值 316 | } 317 | j_MD5Init(&v15); 318 | j_MD5Update((int)&v15, (int)v14, 64); 319 | j_MD5Update((int)&v15, v10, v9); 320 | j_MD5Final(a5, &v15); 321 | j_MD5Init(&v15); 322 | j_MD5Update((int)&v15, (int)v13, 64); 323 | j_MD5Update((int)&v15, a5, 16); 324 | j_MD5Final(a5, &v15); 325 | return _stack_chk_guard; 326 | ``` 327 | 328 | ### 1.5.2 手算HMAC-SHA1 329 | 330 | 明文: test (utf8) 331 | 332 | 密钥: 2111 (hex) 333 | 334 | 结果:6e3a2a24b997b7138fcc48a56427d196a056bf8b 335 | 336 | 第0步:密钥扩展 337 | 338 | > 对密钥扩展到sha1的分组大小64字节(128位16进制数) 339 | > 340 | > 怎么查看分组大小: [https://zh.wikipedia.org/wiki/SHA%E5%AE%B6%E6%97%8F](https://zh.wikipedia.org/wiki/SHA家族),资料区块长度列:sha1 512位=64字节=128位16进制数。 341 | 342 | > 密钥填充到128位:21110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 343 | 344 | 第一步:密钥扩展后的结果与ipad(0x36)异或 345 | 346 | 347 | 348 | > 结果为:17273636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636 349 | 350 | 第二步:append拼接 351 | 352 | > 明文的16进制追加到上一步的结果中 353 | > 354 | > test的hex为74657374,追加到上一步结果后1727363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363674657374 355 | 356 | 第三步:对第二步结果进行sha1 357 | 358 | 输入是hex,添加 from hex 359 | 360 | 361 | 362 | > 结果为:c765a87a411d40e734a219f863b65e25b18cfd4d 363 | 364 | 第四步:密钥扩展后的结果与opad(0x5c)异或 365 | 366 | 7d4d5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c 367 | 368 | 第五步 :把第四步异或的值与第三步sha1的值拼接在一起 369 | 370 | 7d4d5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5cc765a87a411d40e734a219f863b65e25b18cfd4d 371 | 372 | 第六步:第5步的值做一个sha1 373 | 374 | 6e3a2a24b997b7138fcc48a56427d196a056bf8b 375 | 376 | -------------------------------------------------------------------------------- /Android/A04/docs/R1_lesson 1-2.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A04/docs/R1_lesson 1-2.pptx -------------------------------------------------------------------------------- /Android/A04/pic/01.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A04/pic/01.a.png -------------------------------------------------------------------------------- /Android/A04/pic/01.b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A04/pic/01.b.png -------------------------------------------------------------------------------- /Android/A04/pic/02.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A04/pic/02.a.png -------------------------------------------------------------------------------- /Android/A05/README.md: -------------------------------------------------------------------------------- 1 | ## 1.1 DES 2 | 3 | ### 1.1.1 简介 4 | 5 | - Data encrypt standard 数据加密标准 6 | - 入参: 64比特(8个字节、16个16进制数) 7 | - key: 64比特(8个字节、16个16进制数) 8 | - 结果: 64比特(8个字节、16个16进制数) 9 | - DES分两部分:明文的处理以及密钥的编排 10 | - 二进制流处理 11 | 12 | ### 1.1.2 手算DES 13 | 14 | - 前置 15 | 16 | input: 0123456789abcdef (hex) 17 | 18 | key: 133457799bbcdff1(hex) 19 | 20 | output: 85e813540f0ab405 (hex) 21 | 22 | 模式: ECB 23 | 24 | - 第0步:初始置换 25 | 26 | 初始置换表: 27 | 28 | ```python 29 | PI = [58, 50, 42, 34, 26, 18, 10, 2, 30 | 60, 52, 44, 36, 28, 20, 12, 4, 31 | 62, 54, 46, 38, 30, 22, 14, 6, 32 | 64, 56, 48, 40, 32, 24, 16, 8, 33 | 57, 49, 41, 33, 25, 17, 9, 1, 34 | 59, 51, 43, 35, 27, 19, 11, 3, 35 | 61, 53, 45, 37, 29, 21, 13, 5, 36 | 63, 55, 47, 39, 31, 23, 15, 7] 37 | ``` 38 | 39 | 需要对`input`重新排列。根据PI表的索引指示,对明文重新排列,58就是找明文第58个 40 | 41 | > 注:数的时候input从1开始不是0, 看PI表的顺序为从左到右然后从上至下) 42 | 43 | input的二进制表现形式为:`00000001 00100011 01000101 01100111 10001001 10101011 11001101 11101111` 44 | 45 | 置换后的结果为:`11001100 00000000 11001100 11111111 11110000 10101010 11110000 10101010` 46 | 47 | - 第一步:密钥的编排 48 | 49 | 密钥的二进制表现形式为:`00010011 00110100 01010111 01111001 10011011 10111100 11011111 11110001` 50 | 51 | 使用PC1(置换选择表1),只有56个位置,用法同上。des密钥一共64位,只有56位被使用。 52 | 53 | ```python 54 | CP_1 = [57, 49, 41, 33, 25, 17, 9, 55 | 1, 58, 50, 42, 34, 26, 18, 56 | 10, 2, 59, 51, 43, 35, 27, 57 | 19, 11, 3, 60, 52, 44, 36, 58 | 63, 55, 47, 39, 31, 23, 15, 59 | 7, 62, 54, 46, 38, 30, 22, 60 | 14, 6, 61, 53, 45, 37, 29, 61 | 21, 13, 5, 28, 20, 12, 4] 62 | ``` 63 | 64 | 置换后的结果为:`1111000 0110011 0010101 0101111 0101010 1011001 1001111 0001111` 65 | 66 | > 注:此时由64为变成了56位 67 | 68 | --------------------------------------------------------------- 69 | 70 | 平等拆成两块: 71 | 72 | Left0:`1111000 0110011 0010101 0101111` 73 | Right0:`0101010 1011001 1001111 0001111` 74 | 75 | 然后进行循环左移,进行一共16轮运算: 76 | 77 | ​ SHIFT = [1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1] 78 | 79 | L1: 对Left0左移1位, 位数 = SHIFT[0] = 1 得到 `1110000 1100110 0101010 1011111` 80 | 81 | R1 : 对right左移1位, 位数 = SHIFT[0] = 1 得到 `1010101 0110011 0011110 0011110` 82 | 83 | 然后进行拼接: 84 | 85 | ​ L1 + R1:1110000 1100110 0101010 1011111 1010101 0110011 0011110 0011110 86 | 87 | 使用PC2(置换选择表2)进行置换,只有48个位置 88 | 89 | ```python 90 | CP_2 = [14, 17, 11, 24, 1, 5, 3, 28, 91 | 15, 6, 21, 10, 23, 19, 12, 4, 92 | 26, 8, 16, 7, 27, 20, 13, 2, 93 | 41, 52, 31, 37, 47, 55, 30, 40, 94 | 51, 45, 33, 48, 44, 49, 39, 56, 95 | 34, 53, 46, 42, 50, 36, 29, 32] 96 | ``` 97 | 98 | L1R1经过置cp_2置换后的结果为: 00011011 00000010 11101111 11111100 01110000 01110010 , 得到了第一个子密钥k1,注意:此时由56为变成了48位 99 | 100 | ------------------------------------ 101 | 102 | L2: 对L1进行左移SHIFT[1]位, 得到 110000 1100110 0101010 10111111 103 | R2: 对R1进行左移SHIFT[1]位, 得到 010101 0110011 0011110 00111101 104 | append后得到L2R2与CP_2继续置换生成k2 105 | 循环往复直到生成k16,16轮的k/子密钥 106 | 107 | - 第二步:明文的处理 108 | 109 | 上文已经对明文的重排并得到了结果:`11001100 00000000 11001100 11111111 11110000 10101010 11110000 10101010`并得到了了`16`个子密钥 110 | 111 | 把重排的结果分两半 112 | L0: `11001100 00000000 11001100 11111111` 113 | 114 | R0: `11110000 10101010 11110000 10101010` 115 | 116 | L1: R0 (总是上一步的R) 117 | 118 | R1: L0 + F(R0, K1) 可以看到得到Rn的公式就是: Rn = Ln -1 + F(Rn -1, kn), 注: 此刻的+号为异或运算 119 | 120 | ------------------- 121 | 122 | F 函数中 123 | 124 | 第一步: E(R0) 和k做异或使用EXPEND表把R0 32位 扩展到48位,因为之后要与密钥异或,密钥都是48位的所以要扩充到48位 125 | 126 | ```python 127 | [ 32, 1, 2, 3, 4, 5, 128 | 4, 5, 6, 7, 8, 9, 129 | 8, 9, 10, 11, 12, 13, 130 | 12, 13, 14, 15, 16, 17, 131 | 16, 17, 18, 19, 20, 21, 132 | 20, 21, 22, 23, 24, 25, 133 | 24, 25, 26, 27, 28, 29, 134 | 28, 29, 30, 31, 32, 1] 135 | ``` 136 | 137 | ​ 得到结果`01111010 00010101 01010101 01111010 00010101 01010101` 138 | 139 | 第二步:E(R0) ^ k,和k做异或 140 | 141 | ​ 得到结果`011000 010001 011110 111010 100001 100110 010100 100111` 此时为48位。 142 | 143 | 第三步:S(E(R0) ^ k) ,在S盒中找到对应的位置。 144 | 145 | ​ 把第二步得到的结果经过`B1B2B3B4B5B6B7B8`此规则分段,那么就会得到: 146 | 147 | ``` 148 | B1: 011000 149 | B2: 010001 150 | B3: 011110 151 | B4: 111010 152 | B5: 100001 153 | B6: 100110 154 | B7: 010100 155 | B8: 100111 156 | ``` 157 | 158 | ​ 以B1`011000`为例,分成两部分: 159 | 160 | - 第一部分:第一位和最后一位 00,对应的 `10进制`为0,也就是第0行 161 | - 第二部分:中间4位为1100,对应的 `10进制`为12列,也就是第12列。 162 | 163 | 在S盒中从0开始数 (从S_BOX第0个索引开始找),那么就代表着s盒的 第一行第12个 -> 就是5 转成二进制为0101。 164 | 165 | ​ 以B2`010001`为例,分成两部分,因为是B2,就从S_BOX[1]开始数: 166 | 167 | - 第一部分:第一位和最后一位 01,对应的 `10进制`为1,也就是第1行 168 | - 第二部分:中间4位为1000,对应的 `10进制`为8。 169 | 170 | 从S_BOX第一个索引开始数(1,8 ) -> 12 转成二进制为1100。 171 | 172 | ​ 最后8轮 * 4位数 S(E(R0) ^ k) 的结果就变成了32位。 173 | 174 | ```python 175 | S_BOX = [ 176 | 177 | [[14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7], 178 | [0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8], 179 | [4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0], 180 | [15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13], 181 | ], 182 | 183 | [[15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10], 184 | [3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5], 185 | [0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15], 186 | [13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9], 187 | ], 188 | 189 | [[10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8], 190 | [13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1], 191 | [13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7], 192 | [1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12], 193 | ], 194 | 195 | [[7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15], 196 | [13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9], 197 | [10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4], 198 | [3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14], 199 | ], 200 | 201 | [[2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9], 202 | [14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6], 203 | [4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14], 204 | [11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3], 205 | ], 206 | 207 | [[12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11], 208 | [10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8], 209 | [9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6], 210 | [4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13], 211 | ], 212 | 213 | [[4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1], 214 | [13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6], 215 | [1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2], 216 | [6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12], 217 | ], 218 | 219 | [[13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7], 220 | [1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2], 221 | [7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8], 222 | [2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11], 223 | ] 224 | ] 225 | ``` 226 | 227 | 第四步:P置换,将S盒后得到的结果经过P表进行置换,重新排列后得到32位。 228 | 229 | ```python 230 | P = [16, 7, 20, 21, 29, 12, 28, 17, 231 | 1, 15, 23, 26, 5, 18, 31, 10, 232 | 2, 8, 24, 14, 32, 27, 3, 9, 233 | 19, 13, 30, 6, 22, 11, 4, 25] 234 | ``` 235 | 236 | 第五步:最后 L0 + f函数 237 | 238 | > 注: 此时+号为异或运算 239 | 240 | 241 | 242 | - 经过上述步骤周而复始最后得到L16R16,将L16 R16 倒换相加, 最后一轮才倒换,别的轮次不用。 243 | 244 | L16: `01000011 01000010 00110010 00110100` 245 | R16: `00001010 01001100 11011001 10010101` 246 | 247 | R16L16: `00001010 01001100 11011001 10010101 01000011 01000010 00110010 00110100` 248 | 249 | - 最后通过PI_1表进行末位置换得到结果 250 | 251 | ```python 252 | PI_1 = [40, 8, 48, 16, 56, 24, 64, 32, 253 | 39, 7, 47, 15, 55, 23, 63, 31, 254 | 38, 6, 46, 14, 54, 22, 62, 30, 255 | 37, 5, 45, 13, 53, 21, 61, 29, 256 | 36, 4, 44, 12, 52, 20, 60, 28, 257 | 35, 3, 43, 11, 51, 19, 59, 27, 258 | 34, 2, 42, 10, 50, 18, 58, 26, 259 | 33, 1, 41, 9, 49, 17, 57, 25]1.13 260 | ``` 261 | 262 | 263 | ### 1.1.3 问题 264 | 265 | - DES的输入规定是64比特,如果输入的是56比特怎么办?或者是20比特?怎么进行填充? 266 | 267 | > des分组标准为8字节,缺几个字节就补0几 268 | > 269 | > 0123456789 5字节 缺三个字节 补充: 0123456789030303 270 | > 271 | > 0123450505050505 272 | > 273 | > 0123060606060606 274 | > 275 | > 0107070707070707 276 | 277 | - 特殊情况 011 1.5字节怎么补充 278 | 279 | >先补充到 0101,在补充 0101060606060606 280 | 281 | - 假如输入就是8字节,那也必须填充,填充一整个分组 282 | 283 | > 0123456789abcdef0808080808080808 284 | > 285 | > 如果输入是0808080808080808,就可以看到一个现象:结果为两个相同的8字节拼在一起 286 | 287 | - 明文可以缺少可以填充(规则pkcs#7),密钥是不可以的必须符合要求 288 | 289 | - 当明文输入大于64比特怎么办?比如100比特长 290 | 291 | > padding填充成128比特,就变成了两个分组大小 292 | 293 | - 每个分组单独处理?还是彼此之间有联系呢? 294 | 295 | > 这就是工作模式,每个分组单独加密,就好像很多个一分组的DES的这种处理方式。 296 | 297 | ### 1.1.4 工作模式 298 | 299 | - ECB 模式 300 | 301 | > 这种模式有很多好处,我们可以直接for 循环,将很长的输入分成对应个数的分组,每个分组得到结果后拼接在一起就行,而且这也意味着可以并行计算。 302 | > 303 | > 如果ECB模式是可行的、安全的,那么我们一定选择它,因为最简单和高效。那也就不会出现别的工作模式了,可惜的是它并不安全。ECB 相同的分组输入,计算后的秘文结果是完全一致的,相同的明文会被加密成相同的密文,这是很危险的。 304 | 305 | ![](pic/ECB.png) 306 | 307 | - 最常用的是CBC模式 308 | 309 | > 其实想法也很朴素,每个明文分组在加密前多一个步骤,和上一个分组的密文块进行异或运算。 310 | > 311 | > 因为第一个明文块没有所谓的“上一个分组的密文块“,所以需要人给一个64比特,或者说8字节的输入,我们叫它初始化向量,IV。 312 | 313 | 接下来想一下,怎么单独的算出它? 314 | 315 | 在cyberchef中验证一下 316 | 317 | > 明文:123456789ABCDEF0 318 | > 319 | > 密钥:133457799BBCDFF1 320 | > 321 | > IV:0123456789ABCDEF 322 | > 323 | > 模式:CBC模式 324 | > 325 | > 结果:0ecb68bac16aece0 7cbadcfa7a974bcc 326 | > 327 | 328 | 按照我们上面的说法,结果的明文应该就是`123456789ABCDEF0`和IV`0123456789ABCDEF`异或的结果。 329 | 330 | 使用cyberchef计算123456789ABCDEF0 ^ 0123456789ABCDEF 得到结果`1317131f1317131f`,单独计算其DES加密结果,注意这儿要用ECB模式: `0ecb68bac16aece0 fdf2e174492922f8`,因为`1317131f1317131f`是一个分组的长度,所以要填充`0808080808080808`, `fdf2e174492922f8`是`08`的结果,所以不用管。可以发现,第一块加密结果`0ecb68bac16aece0`正是我们所预期的。 331 | 332 | 接下来看一下第二块,第二块即0808080808080808,按照CBC的规则计算 0ecb68bac16aece0 ^ 0808080808080808 = `06c360b2c962e4e8`,单独计算ECB下的`06c360b2c962e4e8` 结果为`7cbadcfa7a974bcc fdf2e174492922f8`,第二块结果`7cbadcfa7a974bcc`也完全正确。 333 | 334 | 我们对CBC模式的理解已经到位了。 335 | 336 | ![](pic/CBC.png) 337 | 338 | - CFB模式 339 | 340 | > 明文:123456789ABCDEF0 341 | > 342 | > 密钥:133457799BBCDFF1 343 | > 344 | > IV:0123456789ABCDEF 345 | > 346 | > 模式:CFB 347 | > 348 | > 结果: 97dc452c95b66af5 349 | > 350 | > 351 | > 352 | > IV即0123456789ABCDEF的des加密结果85e813540f0ab405 353 | > 354 | > 85e813540f0ab405 与 123456789ABCDEF0 的异或结果是97dc452c95b66af5 355 | 356 | ![](pic/CFB.png) 357 | 358 | - OFB 359 | 360 | > 明文:123456789ABCDEF0 361 | > 362 | > 密钥:133457799BBCDFF1 363 | > 364 | > IV:0123456789ABCDEF 365 | > 366 | > 模式:OFB 367 | > 368 | > 结果: 97dc452c95b66af5 369 | > 370 | > 即一个分组的OFB与CFB是一样一样的 371 | 372 | 两个分组的计算: 373 | 374 | > 明文:123456789ABCDEF0 123456789ABCDEF0 375 | > 376 | > 密钥:133457799BBCDFF1 377 | > 378 | > IV:0123456789ABCDEF 379 | > 380 | > 模式:OFB 381 | > 382 | > 结果:97dc452c95b66af5 759a2c51fb637db5 383 | 384 | 直接观察第二个分组`759a2c51fb637db5`是如何计算出来呢? 385 | 386 | 它是明文和加密两次的IV的异或结果 387 | 388 | 明文:`123456789ABCDEF0` 加密第一次:`85e813540f0ab405` 加密第二次 `67ae7a2961dfa345f`,最后异或 67ae7a2961dfa345f ^ 123456789ABCDEF0 = `759a2c51fb637db5` 389 | 390 | ![](pic/OFB.png) 391 | 392 | ### 1.1.5 DES算法的细节 393 | 394 | DES算法虽然不算复杂,但可以说是划时代的加密算法。 395 | 396 | ### 1.1.6 参考 397 | 398 | - [对称加密的逆向特征_zhangmiaoping23的专栏-CSDN博客_aes逆向](https://blog.csdn.net/zhangmiaoping23/article/details/8949290) 399 | 400 | - https://ctf-wiki.org/crypto/blockcipher/des/ 401 | 402 | - [IDAPython实战项目——DES算法识别 - 安全客,安全资讯平台 (anquanke.com)](https://www.anquanke.com/post/id/177808#h3-5) 403 | 404 | - https://bbs.pediy.com/thread-90593.htm 405 | 406 | ## 1.2 3DES 407 | 408 | - 三重DES是什么? 不是把DES做三遍。 409 | - 先加密后解密再加密,这就是标准的3DES,也叫EDE方案,即Encrypt-Decrypt-Encrypt方案。解密时就是解密-加密-解密。 410 | - 需要传入24个字节或者说三个密钥 411 | 412 | * 前8字节是第一步DES加密的密钥 413 | * 中间8字节是第二步DES解密的密钥 414 | * 最后8字节是第三步DES加密的密钥 415 | 416 | - 为什么要做这种奇怪的设计呢? 417 | 418 | 1.DES的第二轮是解密,但因为第二轮的密钥并不是真不是正确的密钥,所以会进一步扰乱数据。 419 | 420 | 2.DES是由IBM公司设计的,3DES的标准自然也是IBM提出的,IBM是这么想的,DES广泛用于银行等系统,这些系统的更新比较慢,因此兼容性问题是很重要的议题。加密-解密-加密的3DES设计,在三个密钥都相同时,就变成了加密-对加密结果解密-再加密,即等同于普通的DES,这就实现了向下兼容。 421 | 422 | ``` 423 | 明文: hex 12345 424 | 密钥: 3个密钥 192bits 3个64位的基础key 0123456789abcdef(hex) 425 | k1k2k3 426 | k1: 0123456789abcdef 427 | k2: 0123456789abcdef 428 | k3: 0123456789abcdef 429 | 3DES结果: a304f525d2d52cbf 430 | DES的结果: a304f525d2d52cbf 431 | 432 | - 结果是一样的,加密 解密 key一样,解密出来的还是原文,在加密就是一遍des加密 433 | - IBM公司为了使DES应用在银行等公司,考虑兼容性,如果换成3个一样的key,结果和DES一样 434 | - k1k2k3不相等 (k1,k2不相等即可,如果k1=k2相等,那么结果又会等与只做了一次k3的DES加密) 435 | - 12345 -> DES加密(k1) -> DES解密(k2) 结果不等于明文, 相当于又做了一次加密,最后又做了一次加密,相当于做了三次加密 436 | - 为什么不直接三次加密嘛,因为是考虑向下兼容,用3个一样的key即可,那么就是简单的DES 437 | ``` 438 | 439 | - Cyberchef 440 | 441 | Cyberchef 用错误的密钥解密,得不出结果? 442 | 因为des分组长度是64比特,分组:8字节 443 | 当使用的input为123456(hex)时,3个字节需要补充为1234560505050505 444 | 当解密的时候,Cyberchef会想把后面的05去掉,给你正确的明文,但是我们用不对的key解密的话后面不带05,就没法解析到05,所以就抱错。 445 | 446 | ![1607018-8564eca6ecbee50d](pic/1607018-8564eca6ecbee50d.webp) 447 | -------------------------------------------------------------------------------- /Android/A05/pic/1607018-8564eca6ecbee50d.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A05/pic/1607018-8564eca6ecbee50d.webp -------------------------------------------------------------------------------- /Android/A05/pic/CBC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A05/pic/CBC.png -------------------------------------------------------------------------------- /Android/A05/pic/CFB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A05/pic/CFB.png -------------------------------------------------------------------------------- /Android/A05/pic/ECB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A05/pic/ECB.png -------------------------------------------------------------------------------- /Android/A05/pic/OFB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A05/pic/OFB.png -------------------------------------------------------------------------------- /Android/A06/README.md: -------------------------------------------------------------------------------- 1 | #### 简介 2 | 3 | ``` 4 | AES 高级加密标准 5 | Rijndael 分组加密荣耀 6 | 7 | 工作模式:ECB、CBC、CFB、OFB 8 | KEY:密钥 9 | IV: 初始化链接变量, 十六个字节长度 10 | PADDING:填充 11 | 12 | 明文: 13 | DES:分组长度64比特,明文会被切成64比特做运算,16个16进制数、8个字节 14 | hex:0123456789abcdef 1111111111111111 2222222222222222 3333333333333333 15 | 明文会被切成4块,64比特为1块 16 | 17 | AES:分组长度128比特,32个16进制数、16个字节 18 | hex:0123456789abcdef1111111111111111 22222222222222223333333333333333 19 | 明文会被切成2块,128比特为1块 20 | 21 | DES中明文都是比特流,最小单位是比特 22 | AES中基于字节的,最小单位是字节 23 | 24 | 密钥: 25 | AES密钥 密钥长度分三种 26 | - 128比特长,16个字节 ----10轮运算 27 | - 192比特长,24个字节 ----12轮运算 28 | - 256比特长,32个字节 ----14轮运算 29 | 不管是aes-128/192/256比特 aes分组大小以及密文输出大小都是不变的。 30 | 假如密钥是255比特长依然会出结果? 31 | 比如:1111111(比特)?不可能是3.5字节,他会在最后一个前面补个0变成: 11 11 11 01 32 | 比如:111111111111111111111111111111111111111111111111111111111111111(252bit),少了4bit 半个字节 33 | 等于:1111111111111111111111111111111111111111111111111111111111111101 34 | 35 | 特征: 36 | AES-128接收16字节的明文输入,16字节的密钥,输出16字节的密文结果。 37 | 当明文恰好是一个分组长度,结果变成了两个分组大小。可能就是aes。 38 | ``` 39 | #### AES算法原理 40 | 41 | ``` 42 | - 密钥的编排 43 | - 明文的运算 44 | 45 | 一切基于字节做操作。 46 | 47 | 举例: 48 | 明文:0123456789abcef to hexdump 30 31 32 33 34 35 36 37 38 39 61 62 63 64 65 66(16个字节) 49 | aes把明文放在一个4*4的矩阵当中,表中每个元素是一个字节大小 50 | 30 34 38 63 51 | 31 35 39 64 52 | 32 36 61 65 53 | 33 37 62 66 54 | 密钥也同明文如此。表中每个元素都是一个字节大小 55 | ``` 56 | 57 | 1. ##### 明文加密流程 58 | 59 | ``` 60 | AES-128 ----10轮运算 61 | 62 | if not ECB: 明文 xor iv 63 | 64 | 首先是一个初始变换 --addRoundKey 65 | - 明文 xor 密钥k (这个key就是我们输入的种子密钥) 66 | 然后是9轮相同的运算 67 | - S盒替换 subBytes 68 | - 循环左移 shiftRows 69 | - 列混淆 mixcolumn 70 | - state xor 密钥 (密钥编排得到的子密钥,不是我们输入的密钥, k1-k9)addRoudKey 71 | 末运算(第10轮) 72 | - S盒替换 73 | - 循环左移 74 | - state xor 密钥 (密钥编排得到的子密钥,不是我们输入的密钥, k10)addRoudKey 75 | ``` 76 | 77 | **1.1 subBytes** 78 | 79 | 大小: 16 * 16 = 256 80 | 81 | ![3](./pic/3.png) 82 | 83 | ``` 84 | S盒行和列使用规则: 85 | 86 | S盒替换前明文数据: 87 | 30 34 38 63 88 | 31 35 39 64 89 | 32 36 61 65 90 | 33 37 62 66 91 | 92 | 从0开始数 93 | 30 就代表第3行第0个 -> 04 94 | 34 就代表第3行第4个 -> 18 95 | 96 | 替换后就变为 97 | 98 | 04 18 07 FB 99 | C7 .. .. .. 100 | 23 .. .. .. 101 | C3 .. .. .. 102 | ``` 103 | 104 | ida如何找s盒? 105 | ida view-> open subviews-> segments data数据断以及rodata只读数据断。 106 | 107 | ![4](./pic/4.png) 108 | 109 | ida中找到s盒,选中0x63右键点击`Byte 0x63`,就识别成了byte数组了,选中右键,点击array,设置size:256。 110 | 111 | ![5](./pic/5.png) 112 | 113 | ![6](./pic/6.png) 114 | 115 | 通过对AES算法原理了解,学会通过查找`S盒`,来确定SO中是否有AES算法。 116 | 117 | **1.2 循环左移** 118 | 119 | ``` 120 | 最小单位字节 121 | 122 | 举例: 123 | d4 e0 b8 1e 124 | 27 bf b4 41 125 | 11 98 5d 52 126 | ae f1 e5 30 127 | 128 | 把上面的循环左移一字节: 129 | d4 e0 b8 1e 第一行左移0个字节 130 | bf b4 41 27 第二行左移一个字节 131 | 5d 52 11 98 第三行左移两个字节 132 | 30 ae f1 e5 第四行左移三个字节 133 | ``` 134 | 135 | ida中循环左移的特征: 136 | 137 | 实现方式1: 138 | 139 | ![7](./pic/7.png) 140 | 141 | 上图中: 142 | 143 | v155[13] = v155[1] 就是1去13 144 | 145 | v155[9] = v155[13] 就是13去9 146 | 147 | 然后就是 9去5、5去1、10去2、2去10 148 | 149 | ``` 150 | 如果明文用a表示的话,可以得到以下结论: 151 | a0 a4 a8 a12 152 | a1 a5 a9 a13 153 | a2 a6 a10 a14 154 | a3 a7 a11 a15 155 | 循环左移后: 156 | a0 a3 a7 a11 157 | a5 a9 a13 a1 158 | a10 a14 a2 a6 159 | a15 a3 a7 a11 160 | 161 | 左移后 a1的位置就是原来的a13,a13的位置就是原来的a9 162 | ``` 163 | 164 | 实现方式2: 165 | 166 | ![8](./pic/8.png) 167 | 168 | ``` 169 | 5去1、9去5 170 | ``` 171 | 172 | 实现方式3: 173 | 174 | ![13](./pic/13.png) 175 | 176 | ida中应用,识别出so中循环左移步骤的代码,然后以此为基点,把上面下面全部打通,可以被当作锚点 177 | 178 | ```c++ 179 | sub_81A0的函数引用 180 | 181 | int sub_7F8C() 182 | { 183 | int v0; // r0 184 | unsigned __int8 i; // [sp+7h] [bp-9h] 185 | 186 | sub_80A0(0); 187 | for ( i = 1; (signed int)i <= 9; ++i ) 188 | { 189 | sub_8120(); // 循环左移上一步就是S盒替换 190 | v0 = sub_81A0(); // 循环左移 191 | sub_8220(v0); // 循环左移下一步就是列混淆 192 | sub_80A0(i); 193 | } 194 | sub_8120(); 195 | sub_81A0(); 196 | return sub_80A0(10); 197 | } 198 | ``` 199 | 200 | **1.3 列混淆** 201 | 202 | ida中特征: 203 | 204 | 会有两个数很关键:0x1B、0x80 这两个数很关键、很明显特征 205 | 206 | ```c++ 207 | int __fastcall sub_8380(unsigned __int8 a1) 208 | { 209 | return (unsigned __int8)(0x1B * (a1 >> 7) ^ 2 * a1); 210 | } 211 | ``` 212 | 213 | 尤其与这个0x1B做异或 ^ 214 | 215 | ![9](./pic/9.png) 216 | 217 | **1.4 通过上述知识做还原** 218 | 219 | ![10](./pic/10.png) 220 | 221 | 初始化的addRoundKey,明文 xor 密钥k (这个key就是我们输入的种子密钥)。 222 | 223 | 2. ##### 密钥的编排(aes-128) 224 | 225 | ``` 226 | 假设我们的密钥为: 227 | d42711aee0bf98f1b8b45de51e415230 228 | 229 | d4 e0 b8 1e 230 | 27 bf b4 41 231 | 11 98 5d 52 232 | ae f1 e5 30 233 | 234 | w0 w1 w2 w3 w4 w5 w6 .....w43 235 | 236 | 237 | 为什么到w43? 238 | 因为是aes-128, 所以每一轮密钥是16个字节,4个w是一轮的密钥,共10轮运算。 239 | 240 | 初始化的addRoundKey用到的key: 241 | key0 = w0w1w2w3 = d42711aee0bf98f1b8b45de51e415230我们的种子密钥,用来做初始变换,根据我们传入的种子密钥获得10个新的子密钥。 242 | hook初始变化addroundKey的异或后面的key,就是我们输入的种子key。 243 | 244 | 9轮运算用到的key分别是: 245 | k1:w4w5w6w7 246 | k2:w8w9w10w11 247 | ...... 248 | k9:w36w37w38w39 249 | 250 | 最后一轮: 251 | k10: w40w41w42w43 252 | 253 | 密钥编排: 254 | 就是根据我们w0-w3传入的密钥,通过密钥编排,生成w4-w43,也叫密钥扩展算法 255 | 密钥扩展:w0-w43,44个w,或者44 *4 = 176个字节 256 | 257 | 文章: 258 | https://blog.csdn.net/qq_28205153/article/details/55798628 259 | ``` 260 | 261 | **2.1 w4-w17的生成** 262 | 263 | ``` 264 | w4 = T(w3) ^ w0, Wn = T(Wn-1) xor Wn-4 每当Windex index为4的倍数时都需要wi-1走一遍T函数 265 | w5、w6、w7时 w5 = w4 ^ w1, wi = wi-1 ^ wi-4(如果i不是4的倍数) 266 | 267 | T函数步骤: 268 | 1. 循环左移1位 269 | 2. S表替换 270 | 3. rcon表异或 271 | 272 | 假如: 273 | w4的计算: 274 | w0 = 2b7e1516,w3 = 0x09cf4f3c,T(w3) = sbox(shiftrow(w3)) ^ rcon[i] 275 | 循环左移1位 -> cf4f3c09 276 | S表替换 -> 8a84eb01 277 | rcon表异或 -> 8b84eb01(rcon表固定的,rcon = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36]) 278 | 最后 w4 = 8b84eb01 ^ w0 = a0fafe17 279 | w5的计算: 280 | w5 = w4 ^ w1 = a0fafe17 ^ w1 281 | ``` 282 | 283 | ![11](./pic/11.png)\ 284 | 285 | ida中特征: 286 | > w43也是密钥扩展的特征,比如 <=43 287 | > <<31 分单双数 288 | > <<30 看是否为4的倍数 289 | 290 | #### so 实现AES算法: 291 | 292 | ``` 293 | 一个AES算法我们要关注哪些内容? 294 | 是AES-128 还是 AES-192 还是 AES-256 295 | 明文是什么 296 | 密钥是什么 297 | 什么模式 ECB还是CBC还是其他 298 | 如果是非ECB模式,那么IV是什么 299 | 明文填充模式呢,是PCKS#7吗? 300 | ``` 301 | 302 | 1. 调用open_ssl封装的EVP。传入结构体,百度搜索,查看参数信息。 303 | ![1](./pic/1.png) 304 | 305 | 2. 直接使用底层的代码,通过hook各个函数,得到信息。 306 | ![2](./pic/2.png) 307 | 308 | #### 拓展 309 | 310 | ``` 311 | 哈希算法:签名校验 312 | 对称加密:DES、AES, 主要应用于对明文的处理 313 | 非对称加密:RSA, 主要功能:提供AES/DES 密钥 314 | 315 | 非对称加密算法:RSA、ECC 316 | 特点:安全性好、 317 | 缺点:运算复杂慢、性能不好 318 | 319 | RSA + AES:混合加密 320 | 321 | findcrypt 可以找到特征 322 | 323 | 逆S盒:https://bbs.pediy.com/thread-266410.htm 324 | S盒 用来加密 325 | 00 0x90 326 | 逆S盒 用来解密 327 | 第9行 第0列 为 00 328 | new_contrary_sbox = [0]*256 329 | 330 | for i in range(256): 331 | line = (new_s_box[i]&0xf0)>>4 332 | rol = new_s_box[i]&0xf 333 | new_contrary_sbox[(line*16)+rol] = i 334 | 335 | print (new_contrary_sbox) 336 | ``` 337 | 338 | ``` 339 | CBC模式分析: 340 | key: 0123456789abcdef str 341 | IV : 1111111111111111 str 342 | input: 0123456789abcdef 0123456789abcdef 两个分组长度 343 | result: 344 | e5b72c539aae45dea57686570b0b5156 345 | 67529ac954d9dee130a26b116dc601c4 346 | 347 | 第一步: 348 | 首先 iv xor 第一个分组的明文块0123456789abcdef 得到 hex: 349 | 01 00 03 02 05 04 07 06 09 08 50 53 52 55 54 57 350 | 结果进行ECB模式加密得到: e5b72c539aae45dea57686570b0b5156 351 | 第二步: 352 | 第二个分组的明文块和第一个秘文块做异或然后进行AES ECB模式加密 353 | e5b72c539aae45dea57686570b0b5156(hex) xor 0123456789abcdef 得到 hex: 354 | d5 86 1e 60 ae 9b 73 e9 9d 4f e7 35 68 6f 34 30 355 | 结果进行ECB模式加密得到: 67529ac954d9dee130a26b116dc601c4 356 | ``` 357 | 358 | ``` 359 | 填充pkcs#7 360 | padding是必须存在的,如果明文已经是16个字节了, 那么也要填充10101010101010101010101010101010 361 | 362 | 输入:pcks#7 000102030405060708090a0b0c0d0e0f 363 | 输出:a07999f0e2bfbe16f99593e984a449b7 377222e061a924c591cd9c27ea163ed4 364 | 365 | aes一个分组会填充10101010101010101010101010101010 366 | 输出:377222e061a924c591cd9c27ea163ed4 377222e061a924c591cd9c27ea163ed4 367 | 368 | 验证: 369 | hex 370 | 01 15个0f的字节 (差15个字节,此时明文是hex,补充hex,hex(15) = 0xf,就是15个0f) 371 | 01 02 14个0e 372 | 01 02 03 13个0d 373 | 01 02 03 04 12个0c 374 | 01 02 03 04 05 11个0b 375 | 01 02 03 04 05 06 10个0a 376 | 注意:类似0f这种padding点 pkcs#7,在hook的时候可以看出他是明文。 377 | ``` 378 | 379 | ``` 380 | 在初始化的addRoundKey时是可以通过异或获得密钥的,但是因为工作模式的不同,是获取不到明文的,例如CBC模式,开始会和iv做异或。 381 | ``` 382 | 383 | ![14](./pic/14.png) 384 | 385 | ![15](./pic/15.png) 386 | 387 | ![16](./pic/16.png) 388 | 389 | 手动验证发现:两个值异或就等于input1,说明r8和r6寄存器的值就是iv和明文。(m 0x3742) 390 | 391 | ![17](./pic/17.png) 392 | 393 | 发现明文和input2做异或,那么他就是第一轮的addRoundKey的 明文 oxr 密钥。 394 | 395 | **SBOX不同表现形式** 396 | 397 | ![18](./pic/18.png) 398 | 399 | 初始置换addRoundKey之后就应该是 S盒替换 为什么这个循环里面都不是S盒,反而是循环外面出现了S盒呢?被魔改了吗? 400 | 401 | 在github或者谷歌搜索: 代码`RijnDael_AES_3629C`里第一个元素`0xC66363A5`,看看有没有线索,发现是有的。[链接](https://github.com/Spittie/advancedtomato-ac/blob/f8d44eac51c1c7c45daf3e5ec324a59549aca6fc/release/src/router/libsodium/src/libsodium/crypto_stream/aes256estream/hongjun/aes-table-be.h)。 402 | 403 | 根据网址里面的命名进行改名,T0就是代码里RignDeal_AES_3629Czaai第一个元素`0xC66363A5`根据网址里查到的,然后进行命名修改。 404 | 405 | ![20](./pic/20.png) 406 | 407 | ![19](./pic/19.png) 408 | 409 | 变成了 T0、T1、T2、T3进行操作。从4个表中取值进行操作。其实是实现方式不同而已。 410 | 411 | 正常用SBOX实现的叫 按照算法描述去实现,样本中这种叫查表法。 412 | 413 | 查表法的好处:以空间换时间加快AES运算,把subBytes、shiftRows、mixcolumn前三个步骤混在一起去了,得到了4个T表。 414 | 415 | ``` 416 | 加解密过程中,加密用Tbox1-4,解密用Tbox5-8,前9轮用T,为什么最后一轮用Sbox不用查表法呢? 417 | 1-9轮 把subBytes、shiftRows、mixcolumn前三个步骤混在一起去了所以用T。 418 | 最面一轮没有mixcolumn,不能用上面混合后的表了,这时候两种方式:可以新增一个新的混合表或者分开来算 s-box、循环左移、state xor 密钥。 419 | 为什么查表法不把addroudkey 和前三步放在一起呢? 420 | 因为addroudkey 密钥是我们生成的,可能会变化, 混合表已经是固定的,所以放不进去。 421 | 怎么把key也放进去? 就是aes白盒--加重混淆,即使有源码都无法简简单单还原出key。 422 | https://bbs.pediy.com/thread-267330.htm 423 | ``` 424 | 425 | ![21](./pic/21.png) 426 | 427 | 上面是查表法下面是分开计算的。 428 | 429 | 但是样本中和S盒还是不一样,有可能是S盒和循环左移搞在一起了。 430 | 431 | -------------------------------------------------------------------------------- /Android/A06/pic/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A06/pic/1.png -------------------------------------------------------------------------------- /Android/A06/pic/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A06/pic/10.png -------------------------------------------------------------------------------- /Android/A06/pic/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A06/pic/11.png -------------------------------------------------------------------------------- /Android/A06/pic/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A06/pic/12.png -------------------------------------------------------------------------------- /Android/A06/pic/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A06/pic/13.png -------------------------------------------------------------------------------- /Android/A06/pic/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A06/pic/14.png -------------------------------------------------------------------------------- /Android/A06/pic/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A06/pic/15.png -------------------------------------------------------------------------------- /Android/A06/pic/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A06/pic/16.png -------------------------------------------------------------------------------- /Android/A06/pic/17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A06/pic/17.png -------------------------------------------------------------------------------- /Android/A06/pic/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A06/pic/18.png -------------------------------------------------------------------------------- /Android/A06/pic/19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A06/pic/19.png -------------------------------------------------------------------------------- /Android/A06/pic/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A06/pic/2.png -------------------------------------------------------------------------------- /Android/A06/pic/20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A06/pic/20.png -------------------------------------------------------------------------------- /Android/A06/pic/21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A06/pic/21.png -------------------------------------------------------------------------------- /Android/A06/pic/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A06/pic/3.png -------------------------------------------------------------------------------- /Android/A06/pic/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A06/pic/4.png -------------------------------------------------------------------------------- /Android/A06/pic/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A06/pic/5.png -------------------------------------------------------------------------------- /Android/A06/pic/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A06/pic/6.png -------------------------------------------------------------------------------- /Android/A06/pic/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A06/pic/7.png -------------------------------------------------------------------------------- /Android/A06/pic/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A06/pic/8.png -------------------------------------------------------------------------------- /Android/A06/pic/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/A06/pic/9.png -------------------------------------------------------------------------------- /Android/B01/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/B01/.DS_Store -------------------------------------------------------------------------------- /Android/B01/README.md: -------------------------------------------------------------------------------- 1 | ## 编译目标Android 7.1.2 2 | 3 | - [源码下载链接: r0ysue编译好的源码](https://github.com/heyhu/AndroidSecurityStudy) 4 | 5 | > 注: 内含多个解压文件,只要解压aosp712r8.zip就行 6 | > 7 | > ![](pic/01.a.png) 8 | 9 | - [手机代号查询](https://source.android.com/setup/start/build-numbers) 10 | 11 | > Android7.1.2搜索android-7.1.2_r8,此版本支持机型最多, 选择前面的Build名称N2G47O 12 | 13 | - [Factory Images下载](https://developers.google.com/android/images) 14 | 15 | > 搜索上面提前的Build号搜索,会有好多版本 16 | > 17 | > 选择"sailfish" for Pixel 18 | > 19 | > | Version | Download | SHA-256 Checksum | 20 | > | ------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | 21 | > | 7.1.2 (N2G47O, May 2017) | [Link](https://dl.google.com/dl/android/aosp/sailfish-n2g47o-factory-f2bc8024.zip) | f2bc8024b015fdf1e79d0ae3da187cb0c371c7fd5a24e384abe75a0c7c1bdb41 | 22 | 23 | - [Driver Binaries设备驱动下载](https://developers.google.com/android/drivers) 24 | 25 | > Pixel binaries for Android 7.1.2 (N2G47O) 两个链接都下载下来 26 | 27 | 28 | 29 | ## 选择kali虚拟机编译 30 | 31 | - 默认账号密码 32 | 33 | > kali / kali 34 | 35 | - 添加超级管理员权限 36 | 37 | > sudo passwd root 38 | 39 | - 设置用户名密码 40 | 41 | > root/toor 自行决定 42 | 43 | - Logout系统,使`root`进行登录即可,再进入就是root系统 44 | 45 | - 修改时区 46 | 47 | > Asia / Shanghai 48 | 49 | - zsh系统修改为bash 50 | 51 | > chsh -s /bin/bash 修改完重启系统生效 52 | 53 | - 设置网络桥接 54 | 55 | - 设置科学上网 56 | 57 | >主机的`vpn`允许局域网连接打开 58 | > 59 | >vim /etc/proxychains 最下面改为socks5设置为主机的sockes 5 ip port,`socks5 192.168.10.8 7891` 60 | > 61 | >proxy_dns 注释掉 62 | > 63 | >proxychains curl ip.sb 查看代理是否挂载成功 64 | 65 | - 安装工具 66 | 67 | > proxychains apt update 68 | > 69 | > apt install jnettop `流量查看工具` htop `进程查看` 70 | 71 | 72 | 73 | ## 磁盘分区 74 | 75 | ``` 76 | 因为该虚拟机默认的八十几G的磁盘空间肯定是不够的,我们给他扩展到450G,要不然报io错误 77 | 进入系统后启动Gparted软件,在unallocated部分右击,选择新建,按照默认即可,即可新建这个370G的ext4分区,点击选择Apply,应用到磁盘。然后将这个新建的磁盘给mount到某个文件夹。 78 | # cd Desktop 79 | # mkdir COMPILE 80 | # 把代码发送到COMPILE文件夹下 81 | # mount /dev/sda3 /root/COMPILE 82 | ``` 83 | 84 | 85 | 86 | ## 拓展Swap 87 | 88 | ``` 89 | dd if=/dev/zero of=swapfile bs=1M count=10240 90 | mkswap swapfile `mkswap创建交换文件` 91 | swapon swapfile `swapon激活` 92 | ``` 93 | 94 | 95 | 96 | ## 下载驱动 97 | 98 | - 把zip包传入kali虚拟机后,使用7z x解压 99 | - 解压完成后,把下好的两个驱动文件拷贝到aosp文件夹下,解压,执行sh文件,会生成vendor目录,之后编译好的镜像就会存在vender.image,否则真机启动不起来。 100 | 101 | 102 | 103 | ## 准备编译环境 104 | 105 | ``` 106 | $ apt update 107 | $ git config --global user.email "you@example.com" 108 | $ git config --global user.name "Your Name" 109 | $ apt install bison tree 110 | $ apt-get install gnupg flex bison build-essential curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses-dev x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev libxml2-utils xsltproc fontconfig 111 | $ apt update 112 | $ apt install libxml2-utils 113 | ``` 114 | 115 | 安装openjdk-8 116 | 117 | ``` 118 | 下载java8 119 | wget https://download.java.net/openjdk/jdk8u41/ri/openjdk-8u41-b04-linux-x64-14_jan_2020.tar.gz 120 | 121 | 编写~/.bashrc 122 | export JAVA_HOME=/root/Desktop/openjdk8/java-se-8u41-ri 123 | export PATH=$JAVA_HOME/bin:$PATH 124 | export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar 125 | 126 | 使java环境生效 127 | source /etc/profile && source /root/.bashrc 128 | 129 | 可以通过-version来确认 130 | java -version 131 | ``` 132 | 133 | 调整python优先级, 使用python2 134 | 135 | ``` 136 | update-alternatives --install /usr/bin/python python /usr/bin/python2 150 137 | update-alternatives --install /usr/bin/python python /usr/bin/python3 100 138 | ``` 139 | 140 | 编译时的报错处理 141 | 142 | ![02.a](pic/02.a.png) 143 | 144 | > 当出现heap不足时有两种解决办法:打开prebuilts/sdk/tools/jack-admin对JACK_SERVER_COMMAND增加-Xmx4096m选项,-cp 前面加 145 | > 146 | > 修改完成后重启jack-admin服务:./jack-admin kill-server、./jack-admin start-server 147 | > 148 | > Android8编译的时候也需要加入 149 | 150 | ![03.a](pic/03.a.png) 151 | 152 | ![04.a](pic/04.a.png) 153 | 154 | 155 | 156 | ## 开始编译 157 | 158 | ``` 159 | # cd /root/Desktop/COMPILE/aosp/ 160 | # export LC_ALL=C 161 | # source build/envsetup.sh 162 | # 选择设备 lunch选择对应的设备,我这里是sailfish,前面驱动也是 163 | # m 程序会自动选择最合适的并行任务数量 164 | 165 | ``` 166 | 167 | **如果要重新编译记得先清理之前的一些东西**,用`m clobber`命令,注意命令`m`是在`. build/envsetup.sh`后才有效的 168 | 169 | 如果重启后要编译,记得先把那个分区挂载上 170 | 171 | ``` 172 | mount /dev/sda3 /root/COMPILE 173 | source /etc/profile && source /root/.bashrc && export LC_ALL=C 174 | . build/envsetup.sh 175 | m clobber 176 | lunch 177 | m 178 | ``` 179 | 180 | 181 | 182 | ## 刷机 183 | 184 | 记住编译完的终端不要退出,用里面自带的fastboot 是和系统一起编译出来的,百分之百成功。 185 | 186 | 下载后的镜像解压zip,并将解压结果中image开头的zip再次解压,进入后只保留`android-info.txt` 187 | 188 | 最后将编译产生的img复制过来,并打包为zip,然后复制zip替换原有zip 189 | 190 | ```bash 191 | 7z x image-sailfish-n2g470.zip 192 | cd image-sailfish-n2g470 193 | rm *.img 194 | cp ~/Desktop/COMPILE/aosp/out/target/product/sailfish/*.img . 195 | zip -r image-sailfish-n2g470.zip * 196 | ``` 197 | 198 | 注意刷机要用到fastboot(adb也可能用到) 199 | 200 | 所以临时把它们添加到环境变量 201 | 202 | ```bash 203 | export PATH=~/myaosp/out/host/linux-x86/bin:$PATH 204 | ``` 205 | 206 | 可以用adb查看下手机刷机前的系统编译日期,对比下刷机之后的日期 207 | 208 | ```bash 209 | adb shell getprop ro.build.date 210 | ``` 211 | 212 | 刷机 213 | 214 | ```bash 215 | ./falsh-all.sh 216 | ``` 217 | 218 | 如果刷机碰到`error: Cannot generate image for userdata`报错 219 | 编辑flash-all.sh,把`-w`去掉,重新刷机 220 | 221 | 222 | 223 | ## 参考链接 224 | 225 | > https://www.anquanke.com/post/id/199898 226 | > 227 | > https://blog.seeflower.dev/archives/12/ 228 | > 229 | > https://blog.csdn.net/click_idc/article/details/80591686 230 | -------------------------------------------------------------------------------- /Android/B01/pic/01.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/B01/pic/01.a.png -------------------------------------------------------------------------------- /Android/B01/pic/02.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/B01/pic/02.a.png -------------------------------------------------------------------------------- /Android/B01/pic/03.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/B01/pic/03.a.png -------------------------------------------------------------------------------- /Android/B01/pic/04.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/B01/pic/04.a.png -------------------------------------------------------------------------------- /Android/B02/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/B02/.DS_Store -------------------------------------------------------------------------------- /Android/B02/README.md: -------------------------------------------------------------------------------- 1 | ## 编译目标Android 7.1.2 2 | 3 | - 目的:aosp源码修改,实现md5、sha1等算法入参和返回值的自吐。 4 | - 环境:以下编译前环境准备、刷机都同于[AOSP源码编译篇](/Android/B01/README.md) 5 | - 系统产出:无root模式 6 | 7 | 8 | 9 | ## Android Studio导入AOSP源码 10 | 11 | - 进入源码根目录,运行如下命令 12 | 13 | > source build/envsetup.sh 14 | > 15 | > mmm development/tools/idegen/ 16 | > 17 | > development/tools/idegen/idegen.sh 18 | 19 | - 导入Android Studio 20 | 21 | > 打开 Android Studio,选择 Open an existing Android Studio project,找到源码目录,点击 Android.ipr,Open,大约等 6 分钟,导入完毕。 22 | 23 | 24 | 25 | ## 修改源码 26 | 27 | 首先要找到对应目标文件在源码哪个目录下,在[源码](http://aosp.opersys.com/xref/android-8.1.0_r81/search?q=MessageDigest.java&project=libcore中搜索MessageDigest.java)中查找,可以看到对应路径。 28 | 29 | 30 | 31 | 修改内容如下: 32 | 33 | ```java 34 | 35 | // 添加库 36 | import java.lang.reflect.InvocationTargetException; 37 | import java.lang.reflect.Method; 38 | 39 | import java.util.*; 40 | import java.lang.*; 41 | import java.io.IOException; 42 | import java.io.ByteArrayOutputStream; 43 | import java.io.PrintStream; 44 | import java.io.InputStream; 45 | import java.io.ByteArrayInputStream; 46 | 47 | import java.nio.ByteBuffer; 48 | 49 | 50 | public abstract class MessageDigest extends MessageDigestSpi { 51 | 52 | /** 53 | * byte数组转hex 54 | * @param bytes 55 | * @return 56 | */ 57 | public static String byteToHex(byte[] bytes){ 58 | String strHex = ""; 59 | StringBuilder sb = new StringBuilder(""); 60 | for (int n = 0; n < bytes.length; n++) { 61 | strHex = Integer.toHexString(bytes[n] & 0xFF); 62 | sb.append((strHex.length() == 1) ? "0" + strHex : strHex); // 每个字节由两个字符表示,位数不够,高位补0 63 | } 64 | return sb.toString().trim(); 65 | } 66 | 67 | /** 68 | * Updates the digest using the specified array of bytes. 69 | * 70 | * @param input the array of bytes. 71 | */ 72 | public void update(byte[] input) { 73 | String inputString = new String(input); 74 | Class logClass = null; 75 | try { 76 | // 本文件没有引用log类,需要使用反射 77 | logClass = this.getClass().getClassLoader().loadClass("android.util.Log"); 78 | } catch (ClassNotFoundException e) { 79 | e.printStackTrace(); 80 | } 81 | Method loge = null; 82 | try { 83 | loge = logClass.getMethod("e",String.class,String.class); 84 | } catch (NoSuchMethodException e) { 85 | e.printStackTrace(); 86 | } 87 | try { 88 | loge.invoke(null,"r0ysue","input is => "+inputString); 89 | Exception e = new Exception("r0ysueINPUT"); 90 | e.printStackTrace(); 91 | } catch (IllegalAccessException e) { 92 | e.printStackTrace(); 93 | } catch (InvocationTargetException e) { 94 | e.printStackTrace(); 95 | } 96 | 97 | engineUpdate(input, 0, input.length); 98 | state = IN_PROGRESS; 99 | } 100 | 101 | /** 102 | * Completes the hash computation by performing final operations 103 | * such as padding. The digest is reset after this call is made. 104 | * 105 | * @return the array of bytes for the resulting hash value. 106 | */ 107 | // public byte[] digest() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { 108 | public byte[] digest(){ 109 | /* Resetting is the responsibility of implementors. */ 110 | byte[] result = engineDigest(); 111 | state = INITIAL; 112 | String resultString = byteToHex(result); 113 | // Log.e("r0ysueDigest","result is => "+ resultString); 114 | Class logClass = null; 115 | try { 116 | logClass = this.getClass().getClassLoader().loadClass("android.util.Log"); 117 | } catch (ClassNotFoundException e) { 118 | e.printStackTrace(); 119 | } 120 | Method loge = null; 121 | try { 122 | loge = logClass.getMethod("e",String.class,String.class); 123 | } catch (NoSuchMethodException e) { 124 | e.printStackTrace(); 125 | } 126 | try { 127 | loge.invoke(null,"r0ysue","result is => "+resultString); 128 | Exception e = new Exception("r0ysueRESULT"); 129 | e.printStackTrace(); 130 | } catch (IllegalAccessException e) { 131 | e.printStackTrace(); 132 | } catch (InvocationTargetException e) { 133 | e.printStackTrace(); 134 | } 135 | 136 | return result; 137 | } 138 | 139 | ``` 140 | 141 | 142 | 143 | ## 开始编译 144 | 145 | ``` 146 | # cd /root/Desktop/COMPILE/aosp/ 147 | # export LC_ALL=C 148 | # source build/envsetup.sh 149 | # lunch选择对应的设备,因为要选择无root版,选项中也没有,手动输入lunch aosp_sailfish-user 150 | # make update-api 更新改动 151 | # make -j4 152 | ``` 153 | 编译成功后刷入手机。 154 | 155 | 156 | 157 | ## 效果如下 158 | 159 | ![](/Android/B02/pic/02.a.png) 160 | 161 | 162 | 163 | ## 参考链接 164 | 165 | > http://wuxiaolong.me/2018/08/15/AOSP3/ 166 | > 167 | > http://aosp.opersys.com/xref/android-8.1.0_r81/xref/libcore/openjdk_java_files.mk#61 168 | > 169 | > http://aosp.opersys.com/ 170 | > 171 | > https://cs.android.com/ 172 | > 173 | > https://source.android.com/setup/build/building 174 | 175 | -------------------------------------------------------------------------------- /Android/B02/pic/01.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/B02/pic/01.a.png -------------------------------------------------------------------------------- /Android/B02/pic/02.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/B02/pic/02.a.png -------------------------------------------------------------------------------- /Android/B03/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/B03/.DS_Store -------------------------------------------------------------------------------- /Android/B03/README.md: -------------------------------------------------------------------------------- 1 | ## 编译目标Android 8.1.0 2 | 3 | - 目的:自制沙箱进行无感知抓包 4 | - 环境:以下编译前环境准备、刷机都同于[AOSP源码编译篇](/Android/B01/README.md) 5 | - 系统产出:无root模式 6 | 7 | 8 | 9 | ## Android Studio导入AOSP源码 10 | 11 | - 进入源码根目录,运行如下命令 12 | 13 | > source build/envsetup.sh 14 | > 15 | > mmm development/tools/idegen/ 16 | > 17 | > development/tools/idegen/idegen.sh 18 | 19 | - 导入Android Studio 20 | 21 | > 打开 Android Studio,选择 Open an existing Android Studio project,找到源码目录,点击 Android.ipr,Open,大约等 6 分钟,导入完毕。 22 | 23 | 24 | 25 | ## 修改源码 26 | 27 | 首先要找到对应目标文件在源码哪个目录下,在[源码](http://aosp.opersys.com/xref/android-8.1.0_r81/search?q=MessageDigest.java&project=libcore中搜索MessageDigest.java)中搜索文件。 28 | 29 | ### 将Charles根证书内置到沙箱系统中 30 | 31 | adb shell进入手机系统中,系统的证书在/etc/security/cacerts目录下,在aosp源码中搜索cacerts。 32 | 33 | ![](/Android/B03/pic/01.a.png) 34 | 35 | ![](/Android/B03/pic/02.a.png) 36 | 37 | ![](/Android/B03/pic/03.a.png) 38 | 39 | 可以看到aosp中 /system/ca-certificates/files中的证书和系统中/etc/security/cacerts中的证书一样,只需把charles证书移植到/system/ca-certificates/files即可。 40 | 41 | ### 沙箱自吐App客户端证书文件和密码 42 | 43 | 官方安卓系统加载证书的代码在java.security.KeyStore类中,其方法为KeyStore.load,第一个参数为证书文件的io流,第二个参数为证书的password。在源码中搜索java.security.KeyStore 44 | 45 | ![](/Android/B03/pic/04.a.png) 46 | 47 | 修改内容如下: 48 | 49 | ```java 50 | package java.security; 51 | 52 | import java.io.*; 53 | import java.lang.reflect.InvocationTargetException; 54 | import java.lang.reflect.Method; 55 | import java.net.URI; 56 | import java.security.cert.Certificate; 57 | import java.security.cert.X509Certificate; 58 | import java.security.cert.CertificateException; 59 | import java.security.spec.AlgorithmParameterSpec; 60 | import java.util.*; 61 | 62 | import javax.crypto.SecretKey; 63 | 64 | import javax.security.auth.DestroyFailedException; 65 | import javax.security.auth.callback.*; 66 | 67 | */ 68 | public final void load(InputStream stream, char[] password) 69 | throws IOException, NoSuchAlgorithmException, CertificateException { 70 | if (password != null) { 71 | String inputPASSWORD = new String(password); 72 | Class logClass = null; 73 | try { 74 | logClass = this.getClass().getClassLoader().loadClass("android.util.Log"); 75 | } catch (ClassNotFoundException e) { 76 | e.printStackTrace(); 77 | } 78 | Method loge = null; 79 | try { 80 | loge = logClass.getMethod("e", String.class, String.class); 81 | } catch (NoSuchMethodException e) { 82 | e.printStackTrace(); 83 | } 84 | try { 85 | loge.invoke(null, "r0ysueKeyStoreLoad", "KeyStore load PASSWORD is => " + inputPASSWORD); 86 | Exception e = new Exception("r0ysueKeyStoreLoad"); 87 | e.printStackTrace(); 88 | } catch (IllegalAccessException e) { 89 | e.printStackTrace(); 90 | } catch (InvocationTargetException e) { 91 | e.printStackTrace(); 92 | } 93 | 94 | Date now = new Date(); 95 | String currentTime = String.valueOf(now.getTime()); 96 | FileOutputStream fos = new FileOutputStream("/sdcard/Download/" + inputPASSWORD + currentTime); 97 | byte[] b = new byte[1024]; 98 | int length; 99 | while ((length = stream.read(b)) > 0) { 100 | fos.write(b, 0, length); 101 | } 102 | fos.flush(); 103 | fos.close(); 104 | 105 | } 106 | 107 | keyStoreSpi.engineLoad(stream, password); 108 | initialized = true; 109 | } 110 | ``` 111 | 112 | ### 沙箱自吐Http请求与响应 113 | 114 | 在源码中搜索java.net.SocketInputStream\java.net.SocketOutputStream 115 | 116 | ![05.a](/Android/B03/pic/05.a.png) 117 | 118 | 修改内容如下: 119 | 120 | ```java 121 | // java.net.SocketInputStream 122 | 123 | package java.net; 124 | 125 | import java.io.FileDescriptor; 126 | import java.io.FileInputStream; 127 | import java.io.IOException; 128 | import java.lang.reflect.InvocationTargetException; 129 | import java.lang.reflect.Method; 130 | import java.nio.channels.FileChannel; 131 | 132 | import dalvik.system.BlockGuard; 133 | import sun.net.ConnectionResetException; 134 | 135 | private int socketRead(FileDescriptor fd, 136 | byte b[], int off, int len, 137 | int timeout) 138 | throws IOException { 139 | int result = socketRead0(fd, b, off, len, timeout); 140 | 141 | if(result>0){ 142 | byte[] input = new byte[result]; 143 | System.arraycopy(b,off,input,0,result); 144 | 145 | String inputString = new String(input); 146 | Class logClass = null; 147 | try { 148 | logClass = this.getClass().getClassLoader().loadClass("android.util.Log"); 149 | } catch (ClassNotFoundException e) { 150 | e.printStackTrace(); 151 | } 152 | Method loge = null; 153 | try { 154 | loge = logClass.getMethod("e",String.class,String.class); 155 | } catch (NoSuchMethodException e) { 156 | e.printStackTrace(); 157 | } 158 | try { 159 | loge.invoke(null,"r0ysueSOCKETresponse","Socket is => "+this.socket.toString()); 160 | loge.invoke(null,"r0ysueSOCKETresponse","buffer is => "+inputString); 161 | Exception e = new Exception("r0ysueSOCKETresponse"); 162 | e.printStackTrace(); 163 | } catch (IllegalAccessException e) { 164 | e.printStackTrace(); 165 | } catch (InvocationTargetException e) { 166 | e.printStackTrace(); 167 | } 168 | 169 | } 170 | return result; 171 | } 172 | ``` 173 | 174 | ```java 175 | // java.net.SocketOutputStream 176 | 177 | package java.net; 178 | 179 | import java.io.FileDescriptor; 180 | import java.io.FileOutputStream; 181 | import java.io.IOException; 182 | import java.lang.reflect.InvocationTargetException; 183 | import java.lang.reflect.Method; 184 | import java.nio.channels.FileChannel; 185 | 186 | import dalvik.system.BlockGuard; 187 | 188 | private void socketWrite(byte b[], int off, int len) throws IOException { 189 | if (len <= 0 || off < 0 || len > b.length - off) { 190 | if (len == 0) { 191 | return; 192 | } 193 | throw new ArrayIndexOutOfBoundsException("len == " + len 194 | + " off == " + off + " buffer length == " + b.length); 195 | } 196 | 197 | FileDescriptor fd = impl.acquireFD(); 198 | try { 199 | BlockGuard.getThreadPolicy().onNetwork(); 200 | socketWrite0(fd, b, off, len); 201 | 202 | 203 | if(len>0){ 204 | byte[] input = new byte[len]; 205 | System.arraycopy(b,off,input,0,len); 206 | 207 | String inputString = new String(input); 208 | Class logClass = null; 209 | try { 210 | logClass = this.getClass().getClassLoader().loadClass("android.util.Log"); 211 | } catch (ClassNotFoundException e) { 212 | e.printStackTrace(); 213 | } 214 | Method loge = null; 215 | try { 216 | loge = logClass.getMethod("e",String.class,String.class); 217 | } catch (NoSuchMethodException e) { 218 | e.printStackTrace(); 219 | } 220 | try { 221 | loge.invoke(null,"r0ysueSOCKETrequest","Socket is => "+this.socket.toString()); 222 | loge.invoke(null,"r0ysueSOCKETrequest","buffer is => "+inputString); 223 | Exception e = new Exception("r0ysueSOCKETrequest"); 224 | e.printStackTrace(); 225 | } catch (IllegalAccessException e) { 226 | e.printStackTrace(); 227 | } catch (InvocationTargetException e) { 228 | e.printStackTrace(); 229 | } 230 | 231 | } 232 | 233 | 234 | } catch (SocketException se) { 235 | if (se instanceof sun.net.ConnectionResetException) { 236 | impl.setConnectionResetPending(); 237 | se = new SocketException("Connection reset"); 238 | } 239 | if (impl.isClosedOrPending()) { 240 | throw new SocketException("Socket closed"); 241 | } else { 242 | throw se; 243 | } 244 | } finally { 245 | impl.releaseFD(); 246 | } 247 | } 248 | ``` 249 | 250 | ### 沙箱自吐Https请求与响应 251 | 252 | 在源码中搜索SslWrapper.java 253 | 254 | ![06.a](/Android/B03/pic/06.a.png) 255 | 256 | 修改内容如下: 257 | 258 | ```java 259 | // TODO(nathanmittler): Remove once after we switch to the engine socket. 260 | int read(FileDescriptor fd, byte[] buf, int offset, int len, int timeoutMillis) 261 | throws IOException { 262 | int result = NativeCrypto.SSL_read(ssl, fd, handshakeCallbacks, buf, offset, len, timeoutMillis) ; 263 | if(result>0){ 264 | byte[] input = new byte[result]; 265 | System.arraycopy(buf,offset,input,0,result); 266 | 267 | String inputString = new String(input); 268 | Class logClass = null; 269 | try { 270 | logClass = this.getClass().getClassLoader().loadClass("android.util.Log"); 271 | } catch (ClassNotFoundException e) { 272 | e.printStackTrace(); 273 | } 274 | Method loge = null; 275 | try { 276 | loge = logClass.getMethod("e",String.class,String.class); 277 | } catch (NoSuchMethodException e) { 278 | e.printStackTrace(); 279 | } 280 | try { 281 | loge.invoke(null,"r0ysueSOCKETresponse","SSL is =>"+this.handshakeCallbacks.toString()); 282 | loge.invoke(null,"r0ysueSOCKETresponse","buffer is => "+inputString); 283 | Exception e = new Exception("r0ysueSOCKETresponse"); 284 | e.printStackTrace(); 285 | } catch (IllegalAccessException e) { 286 | e.printStackTrace(); 287 | } catch (InvocationTargetException e) { 288 | e.printStackTrace(); 289 | } 290 | 291 | } 292 | return result; 293 | } 294 | 295 | // TODO(nathanmittler): Remove once after we switch to the engine socket. 296 | void write(FileDescriptor fd, byte[] buf, int offset, int len, int timeoutMillis) 297 | throws IOException { 298 | 299 | 300 | if(len>0){ 301 | byte[] input = new byte[len]; 302 | System.arraycopy(buf,offset,input,0,len); 303 | 304 | String inputString = new String(input); 305 | Class logClass = null; 306 | try { 307 | logClass = this.getClass().getClassLoader().loadClass("android.util.Log"); 308 | } catch (ClassNotFoundException e) { 309 | e.printStackTrace(); 310 | } 311 | Method loge = null; 312 | try { 313 | loge = logClass.getMethod("e",String.class,String.class); 314 | } catch (NoSuchMethodException e) { 315 | e.printStackTrace(); 316 | } 317 | try { 318 | loge.invoke(null,"r0ysueSSLrequest","SSL is => "+this.handshakeCallbacks.toString()); 319 | loge.invoke(null,"r0ysueSSLrequest","buffer is => "+inputString); 320 | Exception e = new Exception("r0ysueSSLrequest"); 321 | e.printStackTrace(); 322 | } catch (IllegalAccessException e) { 323 | e.printStackTrace(); 324 | } catch (InvocationTargetException e) { 325 | e.printStackTrace(); 326 | } 327 | } 328 | 329 | NativeCrypto.SSL_write(ssl, fd, handshakeCallbacks, buf, offset, len, timeoutMillis); 330 | } 331 | ``` 332 | 333 | 334 | 335 | ## 开始编译 336 | 337 | ``` 338 | # cd /root/Desktop/COMPILE/aosp/ 339 | # export LC_ALL=C 340 | # source build/envsetup.sh 341 | # lunch选择对应的设备,因为要选择无root版,选项中也没有,手动输入lunch aosp_sailfish-user 342 | # make update-api 更新改动 343 | # make -j4 344 | ``` 345 | 346 | 编译成功后刷入手机。 347 | 348 | 349 | 350 | ## 参考链接 351 | 352 | > https://bbs.pediy.com/thread-264283.htm 353 | -------------------------------------------------------------------------------- /Android/B03/pic/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/B03/pic/.DS_Store -------------------------------------------------------------------------------- /Android/B03/pic/01.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/B03/pic/01.a.png -------------------------------------------------------------------------------- /Android/B03/pic/02.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/B03/pic/02.a.png -------------------------------------------------------------------------------- /Android/B03/pic/03.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/B03/pic/03.a.png -------------------------------------------------------------------------------- /Android/B03/pic/04.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/B03/pic/04.a.png -------------------------------------------------------------------------------- /Android/B03/pic/05.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/B03/pic/05.a.png -------------------------------------------------------------------------------- /Android/B03/pic/06.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/B03/pic/06.a.png -------------------------------------------------------------------------------- /Android/B04/README.md: -------------------------------------------------------------------------------- 1 | ## 1.1 刷机 2 | 3 | 谷歌搜 APKMirror、APKPure 可以下载谷歌apk 4 | 5 | 经常用的两个版本:android-8.1.0_r1、android-7.1.2_r8。 6 | 7 | 先去源码库里选择对应型号,找到最前面的aosp代码,去其他两个网址搜索。 8 | 9 | ### 1.1.1 Twrp安装(刷机修复备份工具) 10 | 11 | ``` 12 | $ 进入网址 点击devices 搜索手机型号。 13 | 14 | $ 点击primary,下载 twrp-pixel-installer-sailfish-3.3.0-0.zip以及twrp-3.3.0-0-sailfish.img。 15 | 16 | $ adb reboot bootloader 进入bootloader 模式,fastboot devices 查看是否有设备 17 | 18 | $ fastboot boot twrp-3.3.0-0-sailfish.img 临时进入 19 | 20 | $ adb push ./twrp-pixel-installer-sailfish-3.3.0-0.zip /sdcard/ 手机必须解锁 21 | 22 | $ 手机进去右滑点击install,选择zip包,往右滑就开始刷了。安装完成后rebot system,do not install 就行了。 23 | 24 | $ 版本对应: 25 | 安卓8.1.0 -> twrp-3.3.0-0-sailfish.img -> magisk 最新版 26 | 安卓7.1 -> twrp-3.2.1-0-sailfish.img -> SR3-SuperSU-v2.82-20170813133244.zip + XposedInstaller_3.1.5.apk 27 | ``` 28 | 29 | 30 | 31 | ### 1.1.2 Magisk同上 32 | 33 | ``` 34 | $ fastboot boot twrp-3.3.0-0-sailfish.img 临时进入 35 | 36 | $ 下载Magisk-v20.4.zip push到sdcard中。 37 | 38 | $ 手机进去点击install,选择zip包,往右滑就开始刷了。 39 | 40 | $ 获取root, adb shell su 就可以了。 41 | ``` 42 | 43 | 44 | 45 | ### 1.1.3 Super su 46 | 47 | 最高只适用android 7 48 | 49 | 下载: 50 | 51 | a)![img](pic/01.a.png) -> SuperSU-v2.82-201705271822.zip 52 | 53 | b)同上twrp安装。 54 | 55 | 56 | 57 | ### 1.1.4 lineage 58 | 59 | lineage 自带网络adb调试。 60 | 61 | 刷机包信息: 62 | 63 | ![img](pic/02.a.png) 64 | 65 | su(arm64) 16.0版本 66 | 67 | ![img](pic/03.a.png) 68 | 69 | ![img](pic/04.a.png) 70 | 71 | ![img](pic/05.a.png) 72 | 73 | ### 1.1.5 谷歌全家桶 74 | 75 | ![img](pic/06.a.png) 76 | 77 | ### 1.1.6 nethunter 78 | 79 | https://www.offensive-security.com/kali-linux-nethunter-download/ 80 | 81 | 82 | 83 | ## 1.2参考链接 84 | 85 | - [系统版本:Codenames, Tags, and Build Numbers](https://source.android.com/setup/start/build-numbers ) 86 | - [系统镜像:Factory Images for Nexus and Pixel Devices](https://developers.google.com/android/images#sailfish ) 87 | - [设备驱动:Driver Binaries for Nexus and Pixel Devices](https://developers.google.com/android/drivers) 88 | - [TWRP](https://twrp.me/google/googlepixel.html ) 89 | - [Magisk](https://github.com/topjohnwu/Magisk/releases ) 90 | - [SuperSU](https://supersuroot.org/download/ ) 91 | - [xposed](https://forum.xda-developers.com/showthread.php?t=3034811 ) 92 | - [nethunter](https://www.offensive-security.com/kali-linux-nethunter-download/) 93 | - [谷歌全家桶](https://opengapps.org/) -------------------------------------------------------------------------------- /Android/B04/pic/01.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/B04/pic/01.a.png -------------------------------------------------------------------------------- /Android/B04/pic/02.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/B04/pic/02.a.png -------------------------------------------------------------------------------- /Android/B04/pic/03.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/B04/pic/03.a.png -------------------------------------------------------------------------------- /Android/B04/pic/04.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/B04/pic/04.a.png -------------------------------------------------------------------------------- /Android/B04/pic/05.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/B04/pic/05.a.png -------------------------------------------------------------------------------- /Android/B04/pic/06.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/B04/pic/06.a.png -------------------------------------------------------------------------------- /Android/C01/README.md: -------------------------------------------------------------------------------- 1 | ## 1.1 环境搭建 2 | 3 | 学习工具: 4 | 5 | ``` 6 | Android Studio、Vscode 7 | NDK、ADB、IDA(keypatch) 8 | ``` 9 | 10 | 学习目标: 11 | 12 | ``` 13 | 1. 用户模式下(数据移动、基本整形运算、分支和调用) 14 | 2. 同步了解指令和机器码 15 | ``` 16 | 17 | 常用命令: 18 | 19 | ``` 20 | C头文件信息目录:Library/Android/sdk/ndk/22.0.7026061/toolchains/llvm/prebuilt/darwin-x86_64/sysroot/usr/include 21 | 模拟器文件路径:/Users/xxx/.android/avd/ 22 | 启动模拟器:emulator -avd Pixel_XL_API_16 23 | ida调试:./android-server & (模拟器采取快照模式,使用后台启动,每次就不用进adb启动了) 24 | 端口映射:adb forward tcp:23946 tcp:23946 25 | ``` 26 | 27 | NDK编译: 28 | 29 | ```makefile 30 | #Android.mk 31 | 32 | LOCAL_PATH := $(call my-dir) 33 | include $(CLEAR_VARS) 34 | LOCAL_ARM_MODE := arm #采用arm还是thumb 35 | LOCAL_MODULE := hello 36 | LOCAL_SRC_FILES := hello.c 37 | include $(BUILD_EXECUTABLE) #不编译成so,编译为可执行文件 38 | ``` 39 | 40 | ```makefile 41 | #Application.mk 42 | 43 | APP_ABI := armeabi-v7a 44 | APP_BUILD_SCRIPT := Android.mk 45 | APP_PLATFORM := android-16 46 | ``` 47 | 48 | ``` 49 | ndk-build NDK_PROJECT_PATH=. NDK_APPLICATION_MK=Application.mk 50 | 生成libs和obj文件: 51 | 1.libs会有一个hello的可执行文件 52 | 2.obj也会有一个hello的可执行文件,是debug版本 53 | adb push hello可执行文件到手机里进行调试 54 | 3./proc/2077/maps 内存分布 55 | ``` 56 | 57 | -------------------------------------------------------------------------------- /Android/C02/README.md: -------------------------------------------------------------------------------- 1 | ## 1.1 寄存器 2 | 3 | ida调试模式下怎么看是arm还是thumb? 寄存器窗口PSR寄存器,看T是0还是1。 4 | 5 | ``` 6 | ida: Debugger -> Attach -> Remote ARMLinux/Android debugger 7 | ``` 8 | 9 | ![img](pic/01.png) 10 | 11 | Thumb模式是1,ARM模式是0。 12 | 13 | ``` 14 | Linux的虚拟地址空间范围为0~4G(intel x86架构32位),Linux内核将这4G字节的空间分为两部分,将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF)供内核使用,称为“内核空间”。而将较低的3G字节(从虚拟地址0x00000000到0xBFFFFFFF)供各个进程使用,称为“用户空间”, 15 | 一般碰到B开头是用户进程地址。elf文件入口是arm 16 | ``` 17 | 18 | ``` 19 | 用户模式下寄存器: 20 | LR: linker指针,调用函数的返回地址 21 | PC:当前地址 22 | PSR:状态寄存器 23 | (MODE:处理器模式,10:用户模式, 24 | F:FIQ 中断禁止位,1:禁止 0允许, 25 | I:中断禁止位,1:禁止 0允许, 26 | A:异常屏蔽位 27 | E:大小端序 0:小端序 1:大端序 linux就是小端序 28 | T:arm还是thumb 29 | ***NZCV整型运算用的*** 30 | N:符号位,负数或小于 31 | Z:0标志位 Z标志位赋值为1就是一定执行 32 | C:进位标志位 33 | V:溢出标志位 34 | ) 35 | ``` 36 | 37 | **arm条件和标志位响应** 38 | 39 | ![img](pic/02.png) 40 | 41 | ``` 42 | N 当用两个补码表示的带符号数进行运算时,N=1表示运算的结果为负数;N=0表示运算的结果为正数或零. 43 | Z Z=1表示运算的结果为零,Z=0表示运算的结果非零。Z标志位赋值为1就是一定执行 44 | C 可以有4种方法设置C的值: 45 | 加法运算(包括CMN):当运算结果产生了进位时(无符号数溢出),C=1,否则C=0。 46 | 减法运算(包括CMP):当运算时产生了借位时(无符号数溢出),C=0,否则C=1。 47 | 对于包含移位操作的非加/减运算指令,C为移出值的最后一位。 48 | 对于其它的非加/减运算指令,C的值通常不会改变。 49 | V 可以有2种方法设置V的值: 50 | 对于加减法运算指令,当操作数和运算结果为二进制的补码表示的带符号数时,V=1表示符号位溢出 51 | 对于其它的非加/减运算指令,V的值通常不会改变。 52 | https://blog.csdn.net/nanfangqiulin/article/details/51122718 53 | 54 | ------------- 55 | 一般机器码最高位E是最常见的,代表着AL,无条件执行,通常会忽略此后缀 56 | 57 | CMPCS R2, R3 本来有个CMP指令,加了一个条件后缀CS 58 | ------------- 59 | ADD R0, R0, R1 arm一般的第一个寄存器就是写入的目标值,r0 = R0 + R1 60 | 61 | ADDS R0, R0, R1 62 | 63 | ADDS和ADD的区别就是操作完后会影响标志位,ADD不会影响标志位。 64 | ------------- 65 | 66 | ADDS R0, R0, R1 r0,0x00000000 r1,0xffffffff,结果r0=0x00000000 带s会影响标志位,因为r0=0所以Z=1, 结果产生了进位时(无符号数溢出了)所以 C=1 67 | 68 | subs r0, r0, r1 r0,0x00000000 r1,0xffffffff,结果r0=0x00000001, 当运算时产生了借位时,C=1,但是此时C没有变成1 69 | subs r0, r0, r1 r0,0x00000002 r1,0x00000001,结果r0=0x00000001, 此时没有借位,但是c=1了 为什么? 70 | 执行加法时对C位的影响是正常的。但是减法时对C位的影响和x86是反的。 71 | 减法的时候,只要看到SUBS指令先把C位置1,C位放在被减位的的第一位,变成了0x10000002,0x10000002-1,此时如果产生了借位C=0,否则 C=1,这时因为我们没借位,所以C被留下来了=1。 72 | ------------- 73 | 1A 00 00 9A BLS loc_EA2C,怎么理解BLS? 74 | B + LS标志位后缀还是BL指令 + S后缀,怎么理解? 75 | bl 指令就是跳转一个地方,同时把返回地址写入他的lr寄存器里。此机器码最高位是9,他的二进制为1001,1001对应条件码就是LS,所以是B + LS条件 76 | 77 | ------------- 78 | 01 00 50 E1 CMP r0, r1 第三列(20位)为奇数一定更新Z标志位,偶数就是不需要更新标志位 79 | 80 | SUBS 既要结果,又要标志寄存器 81 | SUB 只要结果,忽略标志寄存器 82 | CMP 忽略结果,只要标志寄存器 83 | 84 | ADDS 既要结果,又要标志寄存器 85 | add 只要结果,忽略标志寄存器 86 | cmn 忽略结果,只要标志寄存器 87 | ``` 88 | 89 | [arm 标志寄存器 ](http://t.zoukankan.com/hjbf-p-13292589.html) 90 | 91 | ## 1.2 指令基本格式 92 | 93 | ``` 94 | arm中没有隐式操作指令,LDR R3, [R5] 带中括号的就是显示操作指令 95 | 96 | 每条指令0-3个操作数,内存操作数和立即操作数不能同时存在,内存操作数至多出现一次,寄存器操作数总在最前 97 | 98 | 操作数3类 :寄存器、内存([R5] 中括号就是内存操作数)、立即数 99 | 100 | LDR R3, [R5],这条指令有寄存器和内存两个操作数,寄存操作数总在最前。 101 | 102 | MOVEQ R2,#0x1F 这条指令有寄存器和立即数两个操作数,寄存操作数总在最前。 103 | 104 | LDR r0,[r1, #4] 第一个操作数r0 寄存器,第二个操作数[r1, #4]内存,#4不是立即数,只是内存的一个索引模式 105 | 106 | MOV R6,R6,LSL R2 第一个操作数R6 寄存器, 第二个操作数(R6,LSL,R2) R6左移R2这么多位 107 | 108 | LDREQ R0, [r4],#4 第一个操作数R6 寄存器, 第二个操作数[r4],#4 内存操作数,,#4的意思为访存之后的附加行为 109 | 110 | lDR R5, =(dword_493D4 - 0x13190) 伪指令,不是原生的arm汇编指令。只要有等号的就是一个内存操作数,相当于看到中括号 111 | 112 | STMFD SP!, {R4,R5,LR} SP!为寄存器操作数,{R4,R5,LR}为寄存器组,寄存器组也是寄存器操作数 113 | 114 | BLS loc_131FC 标签这种就是立即数操作数 115 | 116 | 特殊MRC有5个操作数,他不是arm指令 117 | ``` 118 | 119 | ## 1.3 读PC寄存器需要注意事项 120 | 121 | ### 1.3.1 arm模式下 122 | 123 | ``` 124 | PC寄存器指在当前位置下,在r0寄存器位置点击edit,赋值一个新地址。 125 | 使用keypatch 修改当前机器码为 MOV PC, R0,意思就是r0的值给PC,下一步,调试就会跳到刚才给R0赋值的地址位置,因为pc就是指向当前位置,实现内存跳。 126 | 127 | MOV R0, PC arm模式下读pc的值就是要地址+8, thumb就是+4,即使遇到跳转也是+8。 128 | ``` 129 | 130 | ``` 131 | 此时的pc地址: 0x6ECA92C, 使用Keypatch修改指令为: ldr r0, [pc], 此指令含义为从pc的内存里读取4字节放在r0里。 132 | [pc]为内存操作数,ida会自动翻译成LDR R0, locret_B6ECA934, 133 | arm读pc会加8,地址为0x0x6ECA934,从这个地址读取4个字节给r0,r0的结果为0x512FFF1E(小端序)。 134 | 135 | libc.so:B6ECA928 00 00 00 EF SVC 0 136 | libc.so:B6ECA92C 00 00 9F E5 LDR R0, locret_B6ECA934 ; Keypatch modified this from: 137 | libc.so:B6ECA92C ; LDMFD SP!, {R4,R7} 138 | libc.so:B6ECA930 00 00 B0 E1 MOVS R0, R0 139 | libc.so:B6ECA934 140 | libc.so:B6ECA934 locret_B6ECA934 ; DATA XREF: libc.so:read+C↑r 141 | libc.so:B6ECA934 1E FF 2F 51 BXPL LR 142 | libc.so:B6ECA938 01 B5 00 EA B B6EE492B 143 | ``` 144 | 145 | ``` 146 | ldr r0, [pc, 4] 意思就是读pc加上4个偏移的内存. ida会优化自动算好LDR R0, =0xE92D0090 147 | 此时的pc为B6ECA930, arm读pc会加8,地址为0x6ECA938,加上4个偏移为0x6eca93c,从这个地址读取4个字节给r0为0xE92D0090(小端序)。 148 | 149 | libc.so:B6ECA930 00 00 B0 E1 MOVS R0, R0 150 | libc.so:B6ECA934 151 | libc.so:B6ECA934 locret_B6ECA934 ; DATA XREF: libc.so:read+C↑r 152 | libc.so:B6ECA934 1E FF 2F 51 BXPL LR 153 | libc.so:B6ECA938 01 B5 00 EA B B6EE492B 154 | libc.so:B6ECA938 ; --------------------------------------------------------------------------- 155 | libc.so:B6ECA93C 90 00 2D E9 write DCD 0xE92D0090 156 | ``` 157 | 158 | ``` 159 | [pc, #4] 4为立即数,一般立即数前面需要加#号 160 | ida中 按d可以将此类locret_B6ECA934 强行改成数据格式。 161 | 减去4个地址就是[pc, #-4] 162 | 此时pc=0xB6EF2934, 加8在减4,r0=0xEA00B501,自动识别出来。 163 | 但是按f8后,结果却不对,为何? 164 | 结果为:0xE7F001F0, 把结果改为 F0 01 F0 E7 指令 使用patch program修改后,发现是一个UND指令,相当于一个断点。 165 | 0xB6EF2934 + 8 -4 = 0xb6ef2938为当前pc的下一指令。 166 | 因为调试器机制,在下断点的时候,点击f8,他会在下一条指令进行注入。而我们计算得到的0xb6ef2938就是为下一条指令,所以实际得到的是断点指令,所以不是我们想象的那样为EA00B501。 167 | 168 | libc.so:B6EF2934 04 00 1F E5 LDR R0, =0xEA00B501 ; Keypatch modified this from: 169 | libc.so:B6EF2934 ; BXPL LR 170 | libc.so:B6EF2934 ; --------------------------------------------------------------------------- 171 | libc.so:B6EF2938 01 B5 00 EA dword_B6EF2938 DCD 0xEA00B501 ; DATA XREF: libc.so:read+14↑r 172 | libc.so:B6EF293C 90 00 2D E9 write DCD 0xE92D0090 173 | ``` 174 | 175 | ### 1.3.2 thumb模式下 176 | 177 | ``` 178 | ldr r0, [pc]。 [pc]为内存操作数,从pc的内存里读取4字节放在r0里。 179 | 180 | libc.so:B6F786B8 DF F8 00 00 LDR.W R0, loc_B6F786BC ; Keypatch modified this from: 181 | libc.so:B6F786B8 ; CMP R0, #0 182 | libc.so:B6F786B8 ; Keypatch modified this from: 183 | libc.so:B6F786B8 ; LDR R0, loc_B6F786C0 184 | libc.so:B6F786B8 ; ITETE GE 185 | libc.so:B6F786BC 186 | libc.so:B6F786BC loc_B6F786BC 187 | libc.so:B6F786BC 23 6D LDR R3, [R4,#0x50] 188 | libc.so:B6F786BE A3 89 189 | 190 | 此时的pc为0xB6F786B8, thumb读pc会加4,地址为0xB6F786BC, 从这个地址读取4个字节给r0会是0x89A36D23吗? 191 | 不是,是89A3DE10。89 A3是对的,在23 6D写入DE10(10 de)看一下(Edit->Path program-> Change byte),为 10 DE: UND #0x10 点击f8,此时pc就是下一条指令,调试模式下一句就是断点,所以不能这么写。 192 | 因为f8断点指令会对下一条指令进行改写,所以读到的就是改写后的,无法正确得到下一条指令。 193 | 打断点和实际运行的时候下一条指令读取是不一样的,可做反调试。读下一个指令是 UND #0x10 就说明是一个断点。 194 | ``` 195 | 196 | ``` 197 | ldr r0, [pc, 4] 198 | libc.so:B6F786BC 01 48 LDR R0, loc_B6F786C2+2 ; Keypatch modified this from: 199 | libc.so:B6F786BC ; UND #0x10 200 | libc.so:B6F786BE 01 48 LDR R0, loc_B6F786C2+2 ; Keypatch modified this from: 201 | libc.so:B6F786BE ; LDRH R3, [R4,#0xC] 202 | libc.so:B6F786C0 1B 18 ADDS R3, R3, R0 203 | libc.so:B6F786C2 204 | libc.so:B6F786C2 loc_B6F786C 205 | libc.so:B6F786C2 23 F4 80 53 BIC.W R3, R3, #0x1000 206 | libc.so:B6F786C6 AC BF ITE GE 207 | libc.so:B6F786C8 23 65 STRGE R3, [R4,#0x50] 208 | libc.so:B6F786CA A3 81 STRLTH R3, [R4,#0xC] 209 | 210 | pc = 0xB6F786BC, ldr r0, [pc, 4],先读pc +4,在加立即数的4,就是0xB6F786BC+4+4 = 0xb6f786c4, 读取4个字节,r0就是0xBFAC5380 211 | 按f8到了0xB6F786BE在写ldr r0, [pc, 4],会发现又出现了R0, loc_B6F786C2+2和上一条指令是一样的这是为什么? 212 | 因为这个地址不是4字节对齐,要进行下对等对齐。C6下对等是c4, 所以值是一样的。thumb指令是变长的,有的2字节有的4字节,需要考虑4字节对齐问题。 213 | ``` 214 | 215 | -------------------------------------------------------------------------------- /Android/C02/pic/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/C02/pic/01.png -------------------------------------------------------------------------------- /Android/C02/pic/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/C02/pic/02.png -------------------------------------------------------------------------------- /Android/C03/README.md: -------------------------------------------------------------------------------- 1 | ## 1.1 mov 2 | 3 | > 如何快速从arm手册查看指令 F5:T32 and A32--F5.1 4 | 5 | ```python 6 | mov指令,不访问内存,没有读写内存的操作。因为不访存所以没有内存操作数,只有两个操作数要么是寄存器要么是立即数。 7 | 从第二个操作数给第一个操作数,所以第一个操作数一定是寄存器。 8 | arm指令长度就是4字节32位,所以立即数不能是任意的32位整形,指令长度不足以表示。 9 | 因为mov三种格式允许操作的立即数最多的就是A2编码16位,所以mov指令下立即数不能超16位。 10 | ``` 11 | 12 | ### 1.1.1 MOV, MOVS (immediate) 13 | 14 | #### A1 15 | 16 | ![](pic/01.png) 17 | 18 | ``` 19 | mov r0,0x80000000 即使立即数超了16位也可以,为什么呢?因为采用了A1的这种方式,这种立即数比较常见,它的有效位只有它的最高位8000。 20 | 02 01 A0 E3 MOV R0, #0x80000000 21 | 22 | hex_str1 = "0xE3a00102" 23 | bin:1110 0011 1010 0000 0000 0001 00000010 24 | 25 | 图上又把后12位拆成2份,8-11位以及0-7位,这个立即数就是把机器码里面的02也就是低8位立即数00000010,进行向右循环移位。移多少位呢,就是imm12的高第8-11位乘2,也就是最后8位00000010 向右移动8-11位*2(0001*2=两位)。 26 | 27 | 8位立即数向右移动,可以移动的范围就是4的2次方也就是0-16,为什么乘2?就是0-32,可以覆盖到0-32中的偶数可以移动的比较全,8位立即数可以向右移动0、2、4、8、16、32。 28 | 29 | 此指令A1作用就是 防止写入0x80000000时把机器码弄长,采用左移的方式。 30 | ``` 31 | 32 | #### A2 33 | 34 | ![](pic/02.png) 35 | 36 | ``` 37 | mov 寄存器,立即数。往寄存器写任意一个16位(imm12+imm4=16)的立即数,所以imm一定不能超过16位,0x1234可以,0x12345不行。 38 | 39 | 34 02 01 E3 MOV R0, #0x1234 40 | hex_str = "0xE3010234" 41 | bin: 1110 0011 0000 0001 0000 001000110100 42 | 43 | 34 12 01 E3 MOV R1, #0x1234 44 | hex_str1 = "0xE3011234" 45 | bin:1110 0011 0000 0001 0001 001000110100 46 | 47 | 倒数第1块后12位(imm12)就是立即数后三个字节0x234,倒数第3块4位(imm4)就是立即数第一个字节0x1,拼起来就是我们的立即数0x1234。 48 | 倒数第2块Rd就是代表寄存器,12-15有4位,2的4次方可以表示0-15的数字,int( "1111", 2)=15也就是寄存器r0-r15,后三个寄存器就是SP、LR、PC。此时我们是r0,看倒数第二块就是0,r1就是0001。 49 | bin(16) =0b10000,16以后只能5位才能表示。 50 | ``` 51 | 52 | ``` 53 | 如何使用mov指令在一个寄存器里写入一个任意的32位立即数? 54 | 首先使用mov写入低16位, mov r0, #0x5678,在使用movt在下一条汇编写入高16位, MOVT R0, #0x1234 55 | ida会自动把两句混成一句,ida会生成一个伪指令,78 06 05 E3 34 02+ mov r0, #0x12345678 56 | arm指令时定长的,它是编译器生成的伪指令。 57 | ``` 58 | 59 | ### 1.1.2 MOV, MOVS (register) 60 | 61 | #### A1 62 | 63 | ![](pic/03.png) 64 | 65 | ``` 66 | mov r0, r1(寄存器,寄存器) 67 | mov寄存器可以带shift的, 01 02 A0 E1 MOV R0, R1,LSL#4, r1左移4位给r0 68 | 此指令两个操作数 第一个r0,第二个操作数R1,LSL#4 左移4位 69 | 70 | hex_str = "0xE1A00201" 71 | bin:1110 0001 1 01 0 0000 0000 0010 000 0 0001 72 | 73 | Rm = 0001 = r1, 操作的寄存器 74 | stype = 00 = LSL 75 | 左移右移通过stype(5-6)两位表示,2的2次方代表4种模式:逻辑左移、逻辑右移、算术右移、循环移位。 76 | 没有算数左移,因为算数左移和逻辑左移是一样的,算术右移是带符号的不等于逻辑右移,循环移位不区分左右。 77 | imm5 = 移位的位数 = 00100 = 4 78 | 移位的数就是imm5,这里imm5不是指立即数而是移多少位,7-11位就是通过5位表示,2的5次方=32就是指可以表示0-31的数字。 79 | 移位的范围是32,因为循环左移1位和循环右移31位是一样的,所以循环移位不区分左右。 80 | Rd = 0000 = r0 81 | 20位为1的话就是MOVS 82 | 83 | lsl r0, r1,4 = MOV R0, R1,LSL#4 84 | 相当于mov指令的宏,另一种写法,ida在翻译的时候都会给翻译成mov指令,所以在ida反编译界面找不到lsl、lsr这种指令,都给翻译成了mov指令。 85 | ``` 86 | 87 | ### 1.1.3 MOV, MOVS (register-shifted register) 88 | 89 | ![](pic/04.png) 90 | 91 | ``` 92 | 寄存器带有寄存器的位移 93 | 94 | MOV R0, R1,LSR R2 同上,只不过imm5立即数换成了Rs,与lsr r0, r1, r2两种相等,反汇编后都是move指令。 95 | ``` 96 | 97 | -------------------------------------------------------------------------------- /Android/C03/pic/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/C03/pic/01.png -------------------------------------------------------------------------------- /Android/C03/pic/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/C03/pic/02.png -------------------------------------------------------------------------------- /Android/C03/pic/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/C03/pic/03.png -------------------------------------------------------------------------------- /Android/C03/pic/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Android/C03/pic/04.png -------------------------------------------------------------------------------- /FRIDA/A01/README.md: -------------------------------------------------------------------------------- 1 | ### Frida: 2 | 3 | 1. 为Frida改成非标准端口:./frida-server-12.10.2-android-arm -l 0.0.0.0:8888 4 | 5 | 2. 标准搭配:frida==12.8.0 frida-tools==5.3.0 objection1.8.4 6 | 7 | 3. 列出手机里所有包名: frida-ps -H 192.168.199.237(手机ip):8888 8 | 9 | 4. 查看frida服务是否可用:frida-ps -U android.process.acore 10 | 11 | 5. 查看进程:frida-ps -U | grep 包名 12 | 13 | 6. 指定多个pid:使用-p参数,指定pid 14 | 15 | 7. 脚本注入: 16 | 1. attach模式:frida -U android.process.acore -l s1.js 17 | > 直接附加到已知已存在的进程 18 | 2. spawn模式:frida -U --no-pause -f com.xes.jazhanghui.activity -l hash.js 19 | > 找到指定包名的app并在启动前注入脚本进去,加“--no-pause”表示直接启动, 不暂停在app启动时 20 | 21 | 8. Options: 22 | 23 | 1. 命令行模式: 24 | 1. -f 为spwan模式,以全新的进程启动一个app。如果不加f,就是先让程序一段时间运行在attach上去。 25 | 2. -l 指定hook脚本 26 | 3. -o xxx.txt 把结果输出到txt文件 27 | 4. --no-pause 继续、恢复执行的意思,如果加-f,不加--no-pause,程序会挂起,需要在命令行手动执行%resume,让程序恢复执行,hook脚本也执行。 28 | 5. F 最前台进程, frida -UF 29 | 30 | 2. 交互模式: 31 | 1. %resume 用命令行启动frida时,进入交互界面后,如果不加--no-pause,要输入此命令,使程序继续执行。 32 | 2. %reload 用来重新加载脚本 33 | 3. Frida 用命令行启动frida时,进入交互界面后,查看环境 34 | 4. console.log('hello') 可以直接运行js命令 35 | 36 | 9. frida hook原理 37 | > 启动frida-server时会注入so,在so层进行java层反射。 38 | ![](pic/03.a.png) 39 | ![](pic/04.a.png) 40 | 41 | 10. 如果某些app检测frida的话可以用[hluda](https://github.com/hluwa/strongR-frida-android) 42 | 11. frida-ps -Ua 查看后台进程 43 | -------------------------------------------------------------------------------- /FRIDA/A01/pic/01.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/A01/pic/01.a.png -------------------------------------------------------------------------------- /FRIDA/A01/pic/02.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/A01/pic/02.a.png -------------------------------------------------------------------------------- /FRIDA/A01/pic/03.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/A01/pic/03.a.png -------------------------------------------------------------------------------- /FRIDA/A01/pic/04.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/A01/pic/04.a.png -------------------------------------------------------------------------------- /FRIDA/A01/pic/planet.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/A01/pic/planet.jpeg -------------------------------------------------------------------------------- /FRIDA/A02/README.md: -------------------------------------------------------------------------------- 1 | ### Objection 2 | ``` 3 | $ 用于配合frida移动探索、默认attach上,如果app没有启动 就默认spawn模式启动 4 | $ 只要objection hook到,frida就可以,底层是调用frida的接口 5 | $ frida-server使用标准端口: objection就可以objection -g com.example.demoso1 explore启动,不用加host、端口 6 | $ 使用网络连接objection:objection -N -h 192.168.199.237 -p 8888 -g com.android.settings explore 7 | $ 启动方式:先尝试直接attach启动,失败后在spwan以新进程的方式来启动 8 | $ hook的时机:有的方法是oncreate方法app初始化执行的,所以用spwan的方式,先敲击命令,objection 先尝试直接attach,失败后在spwan以新进程的方式来启动。在点开软件,就可以hook到初始化的方法 9 | ``` 10 | 11 | 1. plugin load 12 | 1. objection -g com.app.name explore -P ~/.objection/plugins 13 | 2. plugin load /Users/xxx/code/Wallbreaker 14 | 15 | 2. Options: 16 | 17 | 1. 命令行模式: 18 | 1. -N 使用网络代替usb 19 | 2. -h 指定ip 20 | 3. -s 指定设备号 21 | 4. -d debug模式 22 | 5. -g 安卓没有root权限,可以把app进行重新打包,即使安卓没有root权限,也可以连接frida 23 | 24 | 2. 交互模式: 25 | 1. env: app常用目录 26 | 2. jobs list: 查看目前当前作业系统,例如列出之前hook的类和方法 27 | 3. jobs kill 编号:杀死job,结束hook操作等 28 | 4. memory list modules: 进入当前程序加载的so,如果系统自己加载的也会显示出来 29 | > so:Service Object(SO)是容器管理的一组对象,完成系统中的业务功能。Service Object完成的工作可能是一系列对数据库操作,文件系统,内存操作的集合,so库 30 | 5. memory list exports libsssl.so --json json.txt:查看so库的导出函数并导出到txt文件中 31 | 6. memory search --string --offsets-only 2d 2d 73 74 72 69 6e 67(dex头):内存搜索 32 | 7. android hooking list classes:列出内存中所有的类 33 | 8. android hooking search classes 类名/关键字: 列出包含指定关键字的类名,可以直接搜索想hook的类名 34 | 9. android hooking list class_methods 类名:列出此类名的所有方法名 35 | 10. android hooking search methods 方法名/关键字 : 从所有的类中搜寻包含此关键字的方法名 36 | 11. android hooking watch class 类名 --dump-args --dump-return --dump-backtrace: hook住类里面的所有函数,app刷新就会打印 37 | > (agent) [yvoqld7tvmm] Called android.util.Base64.encodeToString([B, int),Called就是被调用 38 | 12. android hooking watch class_method android.util.Base64.encodeToString --dump-args --dump-backtrace --dump-return: hook住类的指定方法,直接打印出调用栈、返回值、参数, 自动hook所有的重载 39 | 13. android heap search instances 类名 --fresh: 搜索此类的实例 40 | 14. android heap execute 实例地址 方法名(不加括号): 直接调用类实例的方法 41 | 15. android hooking list activities:列出所有activity 42 | 16. android intent launch_activity com.bk.base.auth.AuthCenterActivity:直接进入某个activity下,可以绕过密码,进入activity 43 | 17. android hooking list services: 列出所有组件 44 | 18. android intent launch_service com.igexin.sdk.PushServic: 可以开启组件,比如设置里面的蓝牙 45 | 19. android hooking generate simple 类名:直接自动生成hook的代码,包含类里面函数hook的方法(不全) 46 | 20. android hooking generate class:自动生成类的hook代码。自动生成的一般不用 47 | 21. objection -g 包名 explore --startup-command "命令": objection在启动时执行命令 48 | > 用于hook例如oncreate这种一瞬即逝的方法 49 | 22. hook一个包下面所有的类 50 | 1. 把hook类的命令全部写到一个txt文件下,然后执行objection -g package_name explore -c n.txt。(批量执行命令) 51 | 2. 先把函数都搜索出来保存到txt文件中,在每行前面加入android hook watch class/method,然后执行objection -g package_name explore -c n.txt。 52 | 23. hook 构造函数,在命令行中需要转义 53 | ![](pic/01.a.png) 54 | -------------------------------------------------------------------------------- /FRIDA/A02/pic/01.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/A02/pic/01.a.png -------------------------------------------------------------------------------- /FRIDA/A03/README.md: -------------------------------------------------------------------------------- 1 | ### Tips 2 | 3 | - 到Activity下,记得看oncreate 4 | 5 | - getprop ro.product.cpu.abi 查看系统CPU处理器 6 | 7 | - whoami 查看当前用户 8 | 9 | - 看雪xctf题可以看别人怎么做,或者在星球直接搜 10 | 11 | - adb shell input text "点击输入密码" 12 | 13 | - adb logcat | grep run 查看日志 14 | 15 | - Termux 安卓使用linux命令 16 | 17 | - du -h * 查看此目录所有文件大小 18 | 19 | - file * 查看文件类型 20 | 21 | - jnettop 监控流量的使用 22 | 23 | - tree -NCfhl | grep -i jni.h 查找***文件在哪 24 | 25 | - frida 代码提示:npm install --save @types/frida-gum 26 | 27 | - jadx -e xxx.apk 导出一个gradle项目 28 | 29 | - 签名头部都是3082 30 | 31 | - siege 32 | 33 | > 压力测试 siege -c10 -r10 "http://192.168.2.6:8899/encrypt POST zsx.json " 34 | 35 | - objection 批量hook 36 | 37 | > 先search所有的类保存到txt文件,在每行的行首加上android hook watch class : sed -i -e 's/^/prefix/' file.txt,使用objection进行批量hook。 38 | 39 | - uname -a 显示系统信息 40 | 41 | > Linux localhost 3.4.0-g0e4eb55 #1 SMP PREEMPT Wed Jun 8 18:45:24 UTC 2016 armv7l 42 | 43 | - nps 44 | 45 | > 使用nps内网渗透到公网,frida_server映射到公网,Xposed配合Nanohttpd映射到公网 46 | 47 | - grep -ril "MainActivity" . 48 | 49 | > 查看此目录脱下来的dex哪个包含指定字符串,可以查看脱下来的壳哪个是正确的。 50 | 51 | - md5sum * 52 | 53 | > 对内容生成md5而不是名字,用于比对文件 54 | 55 | - grep -o 60874635828 2020-11-16.json | wc -l 56 | 57 | > 输出文件内包含符合RE字符串的数量 58 | 59 | - objection 加构造函数 60 | 61 | > return clazz["class"].getDeclaredMethods().concat(clazz.class.getDeclaredConstructors()).map(function (method) {return method.toGenericString();}) 62 | 63 | - curl 64 | 65 | > curl -s -X POST "http://192.168.2.6:8899/encrypt" -H "Content-Type: application/x-www-form-urlencoded" -d "r0ysue" 66 | 67 | - 手机端口映射 68 | 69 | > adb forward tcp:8889 tcp:8889 手机8889映射电脑8889 70 | 71 | - Wallbreaker 72 | 73 | > 搜索实例的时候不一定用类名,可以使用objection 搜索出的实例地址。 74 | 75 | - 遇到Frida反调试咋整?修改AOSP源码打印 76 | 77 | > https://bbs.pediy.com/thread-255653.htm 78 | 79 | - 强制安装32位apk 80 | 81 | > adb install --abi armeabi-v7a xxx.apk 82 | 83 | - 脱壳不全,想查看具体某一个类 84 | 85 | > 使用frida_fart/dumpclass(classname) 86 | 87 | - strings ***.so 88 | 89 | > 查看so文件下的函数,可以使用grep过滤。|grep -i java 90 | 91 | - 查看目标app最顶层Activity 92 | 93 | > adb shell dumpsys activity top |grep heyhu 94 | > 95 | > 进入调试模式:am start -D -n com.heyhu.openso/.MainActivity 96 | 97 | - jadx 反编译失败,代码中含有smali代码 98 | > jadx-gui --show-bad-code test.apk 99 | 100 | 101 | ### Tool 102 | 103 | 1. jnitrace:jni 104 | 2. frida-trace:libc 105 | 3. jeb、ghidra 106 | 4. ZenTracer:批量hook 107 | 5. DEXDump/FART/Youpk:脱壳 108 | 6. jadx 最新版支持多选dex文件 109 | 7. [Hook Event](https://github.com/heyhu/frida-agent-example/blob/master/code/tools/hook_event.js) 110 | 8. inspeckage 111 | -------------------------------------------------------------------------------- /FRIDA/B01/pic/01.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/B01/pic/01.a.png -------------------------------------------------------------------------------- /FRIDA/B01/pic/01.b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/B01/pic/01.b.png -------------------------------------------------------------------------------- /FRIDA/B01/pic/01.c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/B01/pic/01.c.png -------------------------------------------------------------------------------- /FRIDA/B01/pic/01.d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/B01/pic/01.d.png -------------------------------------------------------------------------------- /FRIDA/B01/pic/01.e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/B01/pic/01.e.png -------------------------------------------------------------------------------- /FRIDA/B01/pic/01.f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/B01/pic/01.f.png -------------------------------------------------------------------------------- /FRIDA/B01/pic/01.g.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/B01/pic/01.g.png -------------------------------------------------------------------------------- /FRIDA/B01/pic/01.h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/B01/pic/01.h.png -------------------------------------------------------------------------------- /FRIDA/B01/raptor_frida_android_trace_fixed.js: -------------------------------------------------------------------------------- 1 | /* 2 | * raptor_frida_android_trace.js - Code tracer for Android 3 | * Copyright (c) 2017 Marco Ivaldi 4 | * 5 | * Frida.re JS script to trace arbitrary Java Methods and 6 | * Module functions for debugging and reverse engineering. 7 | * See https://www.frida.re/ and https://codeshare.frida.re/ 8 | * for further information on this powerful tool. 9 | * 10 | * "We want to help others achieve interop through reverse 11 | * engineering" -- @oleavr 12 | * 13 | * Many thanks to @inode-, @federicodotta, @leonjza, and 14 | * @dankluev. 15 | * 16 | * Example usage: 17 | * # frida -U -f com.target.app -l raptor_frida_android_trace.js --no-pause 18 | * 19 | * Get the latest version at: 20 | * https://github.com/0xdea/frida-scripts/ 21 | */ 22 | 23 | // generic trace 24 | function trace(pattern) 25 | { 26 | var type = (pattern.toString().indexOf("!") === -1) ? "java" : "module"; 27 | 28 | if (type === "module") { 29 | console.log("module") 30 | 31 | // trace Module 32 | var res = new ApiResolver("module"); 33 | var matches = res.enumerateMatchesSync(pattern); 34 | var targets = uniqBy(matches, JSON.stringify); 35 | targets.forEach(function(target) { 36 | try{ 37 | traceModule(target.address, target.name); 38 | } 39 | catch(err){} 40 | }); 41 | 42 | } else if (type === "java") { 43 | 44 | console.log("java") 45 | 46 | // trace Java Class 47 | var found = false; 48 | Java.enumerateLoadedClasses({ 49 | onMatch: function(aClass) { 50 | if (aClass.match(pattern)) { 51 | found = true; 52 | console.log("found is true") 53 | 54 | console.log("before:"+aClass) 55 | //var className = aClass.match(/[L](.*);/)[1].replace(/\//g, "."); 56 | var className = aClass.match(/[L]?(.*);?/)[1].replace(/\//g, "."); 57 | console.log("after:"+className) 58 | traceClass(className); 59 | 60 | 61 | } 62 | }, 63 | onComplete: function() {} 64 | }); 65 | 66 | // trace Java Method 67 | if (!found) { 68 | try { 69 | traceMethod(pattern); 70 | } 71 | catch(err) { // catch non existing classes/methods 72 | console.error(err); 73 | } 74 | } 75 | } 76 | } 77 | 78 | // find and trace all methods declared in a Java Class 79 | function traceClass(targetClass) 80 | { 81 | 82 | console.log("entering traceClass") 83 | 84 | var hook = Java.use(targetClass); 85 | var methods = hook.class.getDeclaredMethods(); 86 | hook.$dispose(); 87 | 88 | console.log("entering pasedMethods") 89 | 90 | var parsedMethods = []; 91 | methods.forEach(function(method) { 92 | try{ 93 | parsedMethods.push(method.toString().replace(targetClass + ".", "TOKEN").match(/\sTOKEN(.*)\(/)[1]); 94 | } 95 | catch(err){} 96 | }); 97 | 98 | console.log("entering traceMethods") 99 | 100 | 101 | var targets = uniqBy(parsedMethods, JSON.stringify); 102 | targets.forEach(function(targetMethod) { 103 | try{ 104 | traceMethod(targetClass + "." + targetMethod); 105 | } 106 | catch(err){} 107 | }); 108 | } 109 | 110 | // trace a specific Java Method 111 | function traceMethod(targetClassMethod) 112 | { 113 | var delim = targetClassMethod.lastIndexOf("."); 114 | if (delim === -1) return; 115 | 116 | var targetClass = targetClassMethod.slice(0, delim) 117 | var targetMethod = targetClassMethod.slice(delim + 1, targetClassMethod.length) 118 | 119 | var hook = Java.use(targetClass); 120 | var overloadCount = hook[targetMethod].overloads.length; 121 | 122 | console.log("Tracing " + targetClassMethod + " [" + overloadCount + " overload(s)]"); 123 | 124 | for (var i = 0; i < overloadCount; i++) { 125 | 126 | hook[targetMethod].overloads[i].implementation = function() { 127 | console.warn("\n*** entered " + targetClassMethod); 128 | 129 | // print backtrace 130 | // Java.perform(function() { 131 | // var bt = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()); 132 | // console.log("\nBacktrace:\n" + bt); 133 | // }); 134 | 135 | // print args 136 | if (arguments.length) console.log(); 137 | for (var j = 0; j < arguments.length; j++) { 138 | console.log("arg[" + j + "]: " + arguments[j]); 139 | } 140 | 141 | // print retval 142 | var retval = this[targetMethod].apply(this, arguments); // rare crash (Frida bug?) 143 | console.log("\nretval: " + retval); 144 | console.warn("\n*** exiting " + targetClassMethod); 145 | return retval; 146 | } 147 | } 148 | } 149 | 150 | 151 | // trace Module functions 152 | function traceModule(impl, name) 153 | { 154 | console.log("Tracing " + name); 155 | 156 | Interceptor.attach(impl, { 157 | 158 | onEnter: function(args) { 159 | 160 | // debug only the intended calls 161 | this.flag = false; 162 | // var filename = Memory.readCString(ptr(args[0])); 163 | // if (filename.indexOf("XYZ") === -1 && filename.indexOf("ZYX") === -1) // exclusion list 164 | // if (filename.indexOf("my.interesting.file") !== -1) // inclusion list 165 | this.flag = true; 166 | 167 | if (this.flag) { 168 | console.warn("\n*** entered " + name); 169 | 170 | // print backtrace 171 | console.log("\nBacktrace:\n" + Thread.backtrace(this.context, Backtracer.ACCURATE) 172 | .map(DebugSymbol.fromAddress).join("\n")); 173 | } 174 | }, 175 | 176 | onLeave: function(retval) { 177 | 178 | if (this.flag) { 179 | // print retval 180 | console.log("\nretval: " + retval); 181 | console.warn("\n*** exiting " + name); 182 | } 183 | } 184 | 185 | }); 186 | } 187 | 188 | // remove duplicates from array 189 | function uniqBy(array, key) 190 | { 191 | var seen = {}; 192 | return array.filter(function(item) { 193 | var k = key(item); 194 | return seen.hasOwnProperty(k) ? false : (seen[k] = true); 195 | }); 196 | } 197 | 198 | // usage examples 199 | setTimeout(function() { // avoid java.lang.ClassNotFoundException 200 | 201 | Java.perform(function() { 202 | 203 | console.log("first entering selector") 204 | trace("com.whatsapp.protocol"); 205 | //trace("exports:*!open*"); 206 | //trace("exports:*!write*"); 207 | //trace("exports:*!malloc*"); 208 | //trace("exports:*!free*"); 209 | 210 | }); 211 | }, 0); -------------------------------------------------------------------------------- /FRIDA/B02/pic/01.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/B02/pic/01.a.png -------------------------------------------------------------------------------- /FRIDA/B02/pic/02.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/B02/pic/02.a.png -------------------------------------------------------------------------------- /FRIDA/B02/pic/03.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/B02/pic/03.a.png -------------------------------------------------------------------------------- /FRIDA/B03/README.md: -------------------------------------------------------------------------------- 1 | ## 1.1 Interceptor对象 2 | 3 | 该对象功能十分强大,函数原型是`Interceptor.attach(target, callbacks)`:参数`target`是需要拦截的位置的函数地址,也就是填某个`so`层函数的地址即可对其拦截,`target`是一个`NativePointer`参数,用来指定你想要拦截的函数的地址,`NativePointer`我们也学过是一个指针。需要注意的是对于`Thumb`函数需要对函数地址`+1`,`callbacks`则是它的回调函数,分别是以下两个回调函数: 4 | 5 | ### 1.1.1 Interceptor.attach 6 | 7 | `onEnter:`函数(`args`):回调函数,给定一个参数`args`,可用于读取或写入参数作为 `NativePointer` 对象的数组。 8 | 9 | `onLeave:`函数(`retval`):回调函数给定一个参数 `retval`,该参数是包含原始返回值的 `NativePointer` 派生对象。可以调用 `retval.replace(1337)` 以整数 `1337` 替换返回值,或者调用 `retval.replace(ptr("0x1234"))`以替换为指针。请注意,此对象在 `OnLeave` 调用中回收,因此不要将其存储在回调之外并使用它。如果需要存储包含的值,请制作深副本,例如:`ptr(retval.toString())`。 10 | 11 | 我们来看看示例代码~ 12 | 13 | ```js 14 | //使用Module对象getExportByNameAPI直接获取libc.so中的导出函数read的地址,对read函数进行附加拦截 15 | Interceptor.attach(Module.getExportByName('libc.so', 'read'), { 16 | //每次read函数调用的时候会执行onEnter回调函数 17 | onEnter: function (args) { 18 | this.fileDescriptor = args[0].toInt32(); 19 | }, 20 | //read函数执行完成之后会执行onLeave回调函数 21 | onLeave: function (retval) { 22 | if (retval.toInt32() > 0) { 23 | /* do something with this.fileDescriptor */ 24 | } 25 | } 26 | }); 27 | ``` 28 | 29 | 通过我们对`Interceptor.attach`函数有一些基本了解了~它还包含一些属性。 30 | 31 | | 索引 | 属性 | 含义 | 32 | | ---- | ------------- | ------------------------------------------------------------ | 33 | | 1 | returnAddress | 返回地址,类型是`NativePointer` | 34 | | 2 | context | 上下文:具有键`pc`和`sp`的对象,它们是分别为`ia32/x64/arm`指定`EIP/RIP/PC`和`ESP/RSP/SP的NativePointer`对象。其他处理器特定的键也可用,例如`eax、rax、r0、x0`等。也可以通过分配给这些键来更新寄存器值。 | 35 | | 3 | errno | 当前`errno`值 | 36 | | 4 | lastError | 当前操作系统错误值 | 37 | | 5 | threadId | 操作系统线程ID | 38 | | 6 | depth | 相对于其他调用的调用深度 | 39 | 40 | 我们来看看示例代码。 41 | 42 | ```js 43 | function frida_Interceptor() { 44 | Java.perform(function () { 45 | //对So层的导出函数getSum进行拦截 46 | Interceptor.attach(Module.findExportByName("libhello.so" , "Java_com_roysue_roysueapplication_hellojni_getSum"), { 47 | onEnter: function(args) { 48 | //输出 49 | console.log('Context information:'); 50 | //输出上下文因其是一个Objection对象,需要它进行接送、转换才能正常看到值 51 | console.log('Context : ' + JSON.stringify(this.context)); 52 | //输出返回地址 53 | console.log('Return : ' + this.returnAddress); 54 | //输出线程id 55 | console.log('ThreadId : ' + this.threadId); 56 | console.log('Depth : ' + this.depth); 57 | console.log('Errornr : ' + this.err); 58 | }, 59 | onLeave:function(retval){ 60 | } 61 | }); 62 | }); 63 | } 64 | setImmediate(frida_Interceptor,0); 65 | ``` 66 | 67 | 我们注入脚本之后来看看执行之后的效果以及输出的这些都是啥,执行的效果图`1-9`。 68 | 69 | [![img](https://p3.ssl.qhimg.com/t016ac097aac6fd0971.png)](https://p3.ssl.qhimg.com/t016ac097aac6fd0971.png) 70 | 71 | 图1-9 终端执行 72 | 73 | ### 1.1.2 Interceptor.detachAll 74 | 75 | 简单来说这个的函数的作用就是让之前所有的`Interceptor.attach`附加拦截的回调函数失效。 76 | 77 | ### 1.1.3 Interceptor.replace 78 | 79 | 相当于替换掉原本的函数,用替换时的实现替换目标处的函数。如果想要完全或部分替换现有函数的实现,则通常使用此函数。,我们也看例子,例子是最直观的!代码如下。 80 | 81 | ```js 82 | function frida_Interceptor() { 83 | Java.perform(function () { 84 | //这个c_getSum方法有两个int参数、返回结果为两个参数相加 85 | //这里用NativeFunction函数自己定义了一个c_getSum函数 86 | var add_method = new NativeFunction(Module.findExportByName('libhello.so', 'c_getSum'), 87 | 'int',['int','int']); 88 | //输出结果 那结果肯定就是 3 89 | console.log("result:",add_method(1,2)); 90 | //这里对原函数的功能进行替换实现 91 | Interceptor.replace(add_method, new NativeCallback(function (a, b) { 92 | //h不论是什么参数都返回123 93 | return 123; 94 | }, 'int', ['int', 'int'])); 95 | //再次调用 则返回123 96 | console.log("result:",add_method(1,2)); 97 | }); 98 | } 99 | ``` 100 | 101 | 我来看注入脚本之后的终端是是不是显示了`3`和`123`见下图`1-10`。 102 | 103 | [![img](https://p2.ssl.qhimg.com/t013fb138fe1c77d80c.png)](https://p2.ssl.qhimg.com/t013fb138fe1c77d80c.png) 104 | 105 | 图1-10 终端执行 106 | 107 | 108 | 109 | ## 1.2 NativePointer对象 110 | 111 | 同等与C语言中的指针 112 | 113 | ### 1.2.1 new NativePointer(s) 114 | 115 | 声明定义NativePointer类型 116 | 117 | ```js 118 | function frida_NativePointer() { 119 | Java.perform(function () { 120 | //第一种字符串定义方式 十进制的100 输出为十六进制0x64 121 | const ptr1 = new NativePointer("100"); 122 | console.log("ptr1:",ptr1); 123 | //第二种字符串定义方式 直接定义0x64 同等与定义十六进制的64 124 | const ptr2 = new NativePointer("0x64"); 125 | console.log("ptr2:",ptr2); 126 | //第三种定数值义方式 定义数字int类型 十进制的100 是0x64 127 | const ptr3 = new NativePointer(100); 128 | console.log("ptr3:",ptr3); 129 | }); 130 | } 131 | setImmediate(frida_NativePointer,0); 132 | 133 | /* 134 | 输出如下,都会自动转为十六进制的0x64 135 | ptr1: 0x64 136 | ptr2: 0x64 137 | ptr3: 0x64 */ 138 | ``` 139 | 140 | ### 1.2.2 运算符以及指针读写API 141 | 142 | 它也能调用以下运算符 143 | [![img](https://p3.ssl.qhimg.com/t0135a7319c873d8d52.png)](https://p3.ssl.qhimg.com/t0135a7319c873d8d52.png) 144 | [![img](https://p3.ssl.qhimg.com/t01821e14d1331f0aef.png)](https://p3.ssl.qhimg.com/t01821e14d1331f0aef.png) 145 | 146 | 看完API含义之后,我们来使用他们,下面该脚本是readByteArray()示例~ 147 | 148 | ```js 149 | function frida_NativePointer() { 150 | Java.perform(function () { 151 | console.log(""); 152 | //拿到libc.so在内存中的地址 153 | var pointer = Process.findModuleByName("libc.so").base; 154 | //读取从pointer地址开始的16个字节 155 | console.log(pointer.readByteArray(0x10)); 156 | }); 157 | } 158 | setImmediate(frida_NativePointer,0); 159 | 160 | /* 161 | 输出如下: 162 | 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 163 | 00000000 7f 45 4c 46 A01 A01 A01 00 00 00 00 00 00 00 00 00 .ELF............ */ 164 | ``` 165 | 166 | 首先我先来用`readByteArray`函数来读取`libc.so`文件在内存中的数据,这样我们方便测试,我们从`libc`文件读取`0x10`个字节的长度,肯定会是`7F 45 4C 46...`因为`ELF`文件头部信息中的`Magic`属性。 167 | 168 | ### 1.2.3 readPointer() 169 | 170 | 咱们直接从`API`索引11开始玩readPointer(),定义是从此内存位置读取`NativePointer`,示例代码如下。省略`function`以及`Java.perform`~ 171 | 172 | ```js 173 | var pointer = Process.findModuleByName("libc.so").base; 174 | console.log(pointer.readByteArray(0x10)); 175 | console.log("readPointer():"+pointer.readPointer()); 176 | 177 | /* 178 | 输出如下。 179 | readPointer():0x464c457f */ 180 | ``` 181 | 182 | 也就是将`readPointer`的前四个字节的内容转成地址产生一个新的`NativePointer`。 183 | 184 | ### 1.2.4 writePointer(ptr) 185 | 186 | 读取ptr指针地址到当前指针 187 | 188 | ```js 189 | //先打印pointer指针地址 190 | console.log("pointer :"+pointer); 191 | //分配四个字节的空间地址 192 | const r = Memory.alloc(4); 193 | //将pointer指针写入刚刚申请的r内 194 | r.writePointer(pointer); 195 | //读取r指针的数据 196 | var buffer = Memory.readByteArray(r, 4); 197 | //r指针内放的pointer指针地址 198 | console.log(buffer); 199 | 200 | /* 201 | 输出如下。 202 | //console.log("pointer :"+pointer); 这句打印的地址 也就是libc的地址 203 | pointer :0xf588f000 204 | //console.log(buffer); 输出buffer 0xf588f000在内存数据会以00 f0 88 f5方式显示 205 | 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 206 | 00000000 00 f0 88 f5 .... */ 207 | ``` 208 | 209 | ### 1.2.5 readS32()、readU32() 210 | 211 | 从该内存位置读取有符号或无符号`8/16/32/etc`或浮点数/双精度值,并将其作为数字返回。这里拿`readS32()、readU32()`作为演示. 212 | 213 | ```js 214 | //从pointer地址读4个字节 有符号 215 | console.log(pointer.readS32()); 216 | //从pointer地址读4个字节 无符号 217 | console.log(pointer.readU32()); 218 | 219 | /* 220 | 输出如下。 221 | 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 222 | 00000000 7f 45 4c 46 A01 A01 A01 00 00 00 00 00 00 00 00 00 .ELF............ 223 | 1179403647 == 0x464c457f 224 | 1179403647 == 0x464c457f */ 225 | ``` 226 | 227 | ### 1.2.6 writeS32()、writeU32() 228 | 229 | 将有符号或无符号`8/16/32/`等或浮点数/双精度值写入此内存位置。 230 | 231 | ```js 232 | //申请四个字节的内存空间 233 | const r = Memory.alloc(4); 234 | //将0x12345678写入r地址中 235 | r.writeS32(0x12345678); 236 | //输出 237 | console.log(r.readByteArray(0x10)); 238 | // writeS32()、writeU32()输出的也是一样的,只是区别是有符号和无符号 239 | 240 | /* 241 | 输出如下。 242 | 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 243 | 00000000 78 56 34 12 00 00 00 00 00 00 00 00 00 00 00 00 xV4............. */ 244 | ``` 245 | 246 | ### 1.2.7 readByteArray(length))、writeByteArray(bytes) 247 | 248 | `readByteArray(length))`连续读取内存`length`个字节,、`writeByteArray`连续写入内存`bytes`。 249 | 250 | ```js 251 | //先定义一个需要写入的字节数组 252 | var arr = [ 0x72, 0x6F, 0x79, 0x73, 0x75, 0x65]; 253 | //这里申请以arr大小的内存空间 254 | const r = Memory.alloc(arr.length); 255 | //将arr数组字节写入r 256 | Memory.writeByteArray(r,arr); 257 | //读取arr.length大小的数组 258 | var buffer = Memory.readByteArray(r, arr.length); 259 | console.log("Memory.readByteArray:"); 260 | console.log(hexdump(buffer, { 261 | offset: 0, 262 | length: arr.length, 263 | header: true, 264 | ansi: false 265 | })); 266 | 267 | /* 268 | 输出如下。 269 | Memory.readByteArray: 270 | 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 271 | 00000000 72 6f 79 73 75 65 roysue */ 272 | ``` 273 | 274 | ### 1.2.8 readCString([size = -1])、writeUtf8String(str) 275 | 276 | `readCString`功能是读取指针地址位置的字节字符串,对应的`writeUtf8String`是写入指针地址位置的字符串处。(这里的`r`是接着上面的代码的变量)。 277 | 278 | ```js 279 | //在这里直接使用readCString读取会把上面的'roysue'字符串读取出来 280 | console.log("readCString():"+r.readCString()); 281 | //这里是写入字符串 也就是 roysue起始位置开始被替换为haha 282 | const newPtrstr = r.writeUtf8String("haha"); 283 | //替换完了之后再继续输出 必然是haha 284 | console.log("readCString():"+newPtrstr.readCString()); 285 | ``` 286 | 287 | 咱们来看看执行的效果~~见下图1-11。 288 | 289 | [![img](https://p2.ssl.qhimg.com/t01e8013edc788aa585.png)](https://p2.ssl.qhimg.com/t01e8013edc788aa585.png) 290 | 291 | 图1-11 终端执行 292 | 293 | 294 | 295 | ## 1.3 NativeFunction对象 296 | 297 | 创建新的`NativeFunction`以调用`address`处的函数(用`NativePointer`指定),其中`rereturn Type`指定返回类型,`argTypes`数组指定参数类型。如果不是系统默认值,还可以选择指定`ABI`。对于可变函数,添加一个‘.’固定参数和可变参数之间的`argTypes`条目,我们来看看官方的例子。 298 | 299 | ```js 300 | // LargeObject HandyClass::friendlyFunctionName(); 301 | //创建friendlyFunctionPtr地址的函数 302 | var friendlyFunctionName = new NativeFunction(friendlyFunctionPtr, 303 | 'void', ['pointer', 'pointer']); 304 | //申请内存空间 305 | var returnValue = Memory.alloc(sizeOfLargeObject); 306 | //调用friendlyFunctionName函数 307 | friendlyFunctionName(returnValue, thisPtr); 308 | ``` 309 | 310 | 我来看看它的格式,函数定义格式为`new NativeFunction(address, returnType, argTypes[, options]),`参照这个格式能够创建函数并且调用`!returnType和argTypes[,]`分别可以填`void、pointer、int、uint、long、ulong、char、uchar、float、double、int8、uint8、int16、uint16、int32、uint32、int64、uint64`这些类型,根据函数的所需要的type来定义即可。 311 | 312 | 在定义的时候必须要将参数类型个数和参数类型以及返回值完全匹配,假设有三个参数都是`int`,则`new NativeFunction(address, returnType, ['int', 'int', 'int'])`,而返回值是`int`则`new NativeFunction(address, 'int', argTypes[, options])`,必须要全部匹配,并且第一个参数一定要是函数地址指针。 313 | 314 | 315 | 316 | ## 1.4 NativeCallback对象 317 | 318 | `new NativeCallback(func,rereturn Type,argTypes[,ABI]):`创建一个由`JavaScript`函数`func`实现的新`NativeCallback`,其中`rereturn Type`指定返回类型,`argTypes`数组指定参数类型。您还可以指定`ABI`(如果不是系统默认值)。有关支持的类型和Abis的详细信息,请参见`NativeFunction`。注意,返回的对象也是一个`NativePointer`,因此可以传递给`Interceptor#replace`。当将产生的回调与`Interceptor.replace()`一起使用时,将调用func,并将其绑定到具有一些有用属性的对象,就像`Interceptor.Attach()`中的那样。我们来看一个例子。如下,利用`NativeCallback`做一个函数替换。 319 | 320 | ```js 321 | Java.perform(function () { 322 | var add_method = new NativeFunction(Module.findExportByName('libhello.so', 'c_getSum'), 323 | 'int',['int','int']); 324 | console.log("result:",add_method(1,2)); 325 | //在这里new一个新的函数,但是参数的个数和返回值必须对应 326 | Interceptor.replace(add_method, new NativeCallback(function (a, b) { 327 | return 123; 328 | }, 'int', ['int', 'int'])); 329 | console.log("result:",add_method(1,2)); 330 | }); 331 | ``` 332 | 333 | -------------------------------------------------------------------------------- /FRIDA/B04/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/B04/.DS_Store -------------------------------------------------------------------------------- /FRIDA/B04/pic/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/B04/pic/01.png -------------------------------------------------------------------------------- /FRIDA/B04/pic/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/B04/pic/02.png -------------------------------------------------------------------------------- /FRIDA/B04/pic/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/B04/pic/03.png -------------------------------------------------------------------------------- /FRIDA/B05/README.md: -------------------------------------------------------------------------------- 1 | ## 1.1 Frida + IDA 动静态SO层算法 2 | 3 | 题目:https://www.52pojie.cn/thread-1369661-1-1.html 4 | 5 | 目标:获取flag,输入到app中,完成验证。 6 | 7 | ### 1.1.1 jadx 分析java源码 8 | 9 | 输入玩密码后,会显示`flag 格式错误,请重试`,直接在jadx源码中搜,或者直接看MainActivity。源码如下: 10 | 11 | ```java 12 | package cn.pojie52.cm01; 13 | 14 | import android.os.Bundle; 15 | import android.view.View; 16 | import android.widget.EditText; 17 | import android.widget.Toast; 18 | import androidx.appcompat.app.AppCompatActivity; 19 | 20 | public class MainActivity extends AppCompatActivity { 21 | public native boolean check(String str); 22 | 23 | static { 24 | System.loadLibrary("native-lib"); 25 | } 26 | 27 | /* access modifiers changed from: protected */ 28 | @Override // androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, androidx.appcompat.app.AppCompatActivity, androidx.fragment.app.FragmentActivity 29 | public void onCreate(Bundle bundle) { 30 | super.onCreate(bundle); 31 | setContentView(R.layout.activity_main); 32 | final EditText editText = (EditText) findViewById(R.id.flag); 33 | findViewById(R.id.check).setOnClickListener(new View.OnClickListener() { 34 | /* class cn.pojie52.cm01.MainActivity.AnonymousClass1 */ 35 | 36 | public void onClick(View view) { 37 | // 删除头尾空白符 38 | String trim = editText.getText().toString().trim(); 39 | if (trim.length() != 30) { 40 | Toast.makeText(MainActivity.this, "flag格式错误,请重试", 0).show(); 41 | } else if (MainActivity.this.check(trim)) { 42 | Toast.makeText(MainActivity.this, "恭喜你,验证正确!", 0).show(); 43 | } else { 44 | Toast.makeText(MainActivity.this, "flag错误,再接再厉", 0).show(); 45 | } 46 | } 47 | }); 48 | } 49 | } 50 | ``` 51 | 52 | 首先可以看到,输入文本的长度必须30位,会调用`check`方法去验证你输入的密码是否正确,从代码中可以看到,`check`方法在so层,so库的名字为libnative-lib.so。 53 | 54 | 如何获取so文件: a) 解压apk中获取 b) Objection中获取加载so库,找到其在手机中对应的目录,adb pull下来。 55 | 56 | 57 | 58 | ### 1.1.2 动静态分析so 59 | 60 | 打开首先点击exports,查看导出函数,可以看到函数名`Java_cn_pojie52_cm01_MainActivity_check`,此函数是一个JNI的静态注册的函数,点击F5,查看c伪代码。 61 | 62 | F5查看伪代码,第一行: 63 | 64 | `__int64 __fastcall Java_cn_pojie52_cm01_MainActivity_check(JNIEnv *a1, __int64 a2, __int64 a3)` 65 | 66 | a1: JNIEnv,a2: jclass/jobject,a3输入的值。 67 | 68 | 注意:类似`result = (*(__int64 (**)(void))(*(_QWORD *)a1 + 1344LL))();`这种形式的代码,选中a1点击y,输入`JNIEnv *`让它转换为`JNI`。如果失败需要导入jni.h,可以查看转换后的代码为`v7 = ((__int64 (__fastcall *)(JNIEnv *, __int64, _QWORD))(*v4)->GetStringUTFChars)(v4, v5, 0LL);`这行代码最终效果为把java的字符串转换为c层的字符串。我们可以按N键修改变量名方便我们进行静态查看。 69 | 70 | 查看`sub_B90(&dest, v10, (__int64)"areyousure??????");` 函数,dest为我们传入的函数,查看它进行了哪些操作。两种方式: 71 | 72 | sub_B90 函数头部信息`unsigned __int64 __fastcall sub_B90(_BYTE *a1, unsigned int a2, __int64 a3)` 73 | 74 | 1. IDA 动态调试 75 | 76 | 把IDA中dbgsrv下的服务端android-server[64] push到手机中。./android-server运行。 77 | 78 | IDA -> go -> Debugger-> Attach -> android debugger 输入手机ip地址进行连接,选择要attach的进程,先点击运行按钮进行放行让app继续执行,点击G输入sub_B90的函数地址,点击下断点,可以选中0x91那选择edit->code转成字节码与静态分析的进行对比,查看我们下的断点位置是否正确: 79 | 80 | ![](pic/01.a.png) 81 | 82 | ![](pic/03.a.png) 83 | 84 | ![](pic/02.a.png) 85 | 86 | 然后点击手机app的验证按钮,只要走过断点的函数,就会被暂停,然后F7、F8进行调试。 87 | 88 | 查看值的两种方法,stack中,寄存器x0中有值才可以点击查看。 89 | 90 | ![](pic/04.a.png) 91 | 92 | ![](pic/05.a.png) 93 | 94 | 可以看到就是我们输入的值。 95 | 96 | 2. Frida 调试: 97 | 98 | 因为其函数第一个参数为*a1,就说明它是一个指针。其值可以在函数运行时改变。 99 | 100 | ```javascript 101 | // 指针 参数程序内改变,需要函数离开时在打印下这个指针 102 | function hook_B90() { 103 | var libnative_addr = Module.findBaseAddress('libnative-lib.so'); 104 | console.log("so base address ->", libnative_addr) 105 | var addr_0xB90 = libnative_addr.add(0xB90); 106 | console.log("addr_0xB90 ->", addr_0xB90) 107 | 108 | Interceptor.attach(addr_0xB90, { 109 | onEnter: function (args) { 110 | this.args0 = args[0] 111 | this.args1 = args[1] 112 | this.args2 = args[2] 113 | 114 | console.log("calling addr_0xB90") 115 | console.log("args1:", hexdump(args[0])) 116 | console.log("args2:", args[1]) 117 | console.log("args3:", Memory.readCString(args[2])) 118 | 119 | }, 120 | onLeave: function (retval) { 121 | console.log("now is retval") 122 | // 原文: 30个1 16进制31 31 31 31 31 31 31-> 函数结束后改变为: e0 6b 37 a1 75 d7 f6 d4 ef 19 c.. 123 | console.log("args1:", hexdump(this.args0)) 124 | console.log("args2:", this.args1) 125 | console.log("args3:", Memory.readCString(this.args2)) 126 | } 127 | }) 128 | } 129 | ``` 130 | 131 | 我们查看其函数内部做的操作,传入值a1的引用`v4 = a1`, v4 的引用`*v4++ ^= *((_BYTE *)&v21 + (unsigned __int8)(*((_BYTE *)&v21 + v13) + v18));`可以看到传入值只有在这两处被引用过,可以直接看出此算法是一个`异或`。 132 | 133 | 异或算法还原: 134 | 135 | ``` 136 | 明文 ^ 密钥 = 密文 137 | 密文 ^ 密钥 = 明文 138 | ``` 139 | 140 | 我们在hook B90时,知道第一个参数就是一个指针`_BYTE *a1`,它在程序运行完指针已经指向了另一个地址,我们可以看到其值已发生改变。 141 | 142 | ``` 143 | calling addr_0xB90 144 | args1: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 145 | 7fe9b0e078 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 1111111111111111 146 | 7fe9b0e088 31 31 31 31 31 31 31 31 31 31 31 31 31 31 00 00 11111111111111.. 147 | 7fe9b0e098 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 148 | 7fe9b0e0a8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 149 | 7fe9b0e0b8 45 39 1b 29 cb 94 1d cf 60 b4 ce 12 00 00 00 00 E9.)....`....... 150 | 151 | 152 | now is retval 153 | args1: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 154 | 7fe9b0e078 e0 6b 37 a1 75 d7 f6 d4 ef 19 c6 c3 57 a0 f9 b4 .k7.u.......W... 155 | 7fe9b0e088 73 ee c8 d1 b3 30 1a 0a 09 52 06 8c 1f 7c 00 00 s....0...R...|.. 156 | 7fe9b0e098 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 157 | 7fe9b0e0a8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 158 | 7fe9b0e0b8 45 39 1b 29 cb 94 1d cf 60 b4 ce 12 00 00 00 00 E9.)....`....... 159 | 7fe9b0e0c8 10 28 c8 12 00 00 00 00 fc 07 1d c8 73 00 00 00 .(..........s... 160 | 161 | ``` 162 | 163 | 获取密钥的两种方式: 164 | 165 | 1. 手动比对 166 | 167 | 0x31 ^ 0xe0、0x31 ^ 0x6b 以此类推得出: 168 | 169 | xorkey = [209, 90, 6, 144, 68, 230, 199, 229, 222, 40, 247, 242, 102, 145, 200, 133, 66, 223, 249, 224, 130, 1, 43, 59, 56, 99, 55, 189, 46, 77] 170 | 171 | 172 | 173 | 2. hook 174 | 175 | hook `*v4++ ^= *((_BYTE *)&v21 + (unsigned __int8)(*((_BYTE *)&v21 + v13) + v18))`这条汇编指令。 176 | 177 | ```javascript 178 | function hook_D58() { 179 | Java.perform(function () { 180 | var libnative = Module.findBaseAddress("libnative-lib.so"); 181 | console.log("libnative: " + libnative); 182 | // 获取异或的字节,开了会报错,但是可以获取 183 | var ishook = true; 184 | var EOR = libnative.add(0xD58); 185 | var eor = []; 186 | var eorlen = 0; 187 | Interceptor.attach(EOR, { 188 | onEnter: function (args) { 189 | if (ishook) { 190 | if (eorlen < 30) { 191 | eor.push(this.context.x12); 192 | eorlen += 1; 193 | } else { 194 | ishook = false; 195 | console.log(eor); 196 | } 197 | } 198 | } 199 | }) 200 | }) 201 | } 202 | ``` 203 | 204 | 205 | 206 | ida中查看,可以看到汇编指令的地址是【D58】,需要的寄存器是x12。(w是32位寄存器,X是64位寄存器) 207 | 208 | 209 | 210 | eor是逻辑异或指令 将r0 和r1中值逻辑异或 存到r3 211 | 212 | ``` 213 | ldr r0, =158 214 | ldr r1, =42 215 | eor r3, r0, r1 216 | ``` 217 | 218 | 继续分析:`v12 = sub_D90((char *)&dest, dest_length);` hook此函数为Base64。 219 | 220 | 查看v12 引用 `while ( *(unsigned __int8 *)(v12 + v24) == *((unsigned __int8 *)&v29 + v24) )` 221 | 222 | v29就是最后比对的值,v29 base64decode 之后是秘文,在用密钥 异或 得出明文。 223 | 224 | 查看v29 的值,也是两种方法。ida动态调试与frida inline hook。x0为我们的值,x9为正确base64的值。 225 | 226 | ![](pic/07.a.png) 227 | 228 | 229 | 230 | frida hook 231 | 232 | 233 | 234 | ``` 235 | function hook_x9() { 236 | // hook寄存器地址,得到对比的正确的base64 237 | var libnative_addr = Module.findBaseAddress('libnative-lib.so'); 238 | console.log("so base address ->", libnative_addr) 239 | var addr_0xB30 = libnative_addr.add(0xB30); 240 | console.log("addr_0xB30 ->", addr_0xB30) 241 | Interceptor.attach(addr_0xB30, { 242 | onEnter: function (args) { 243 | console.log(Memory.readCString(this.context.x9)); 244 | // console.log(Memory.readByteArray(this.context.x9, 50)); 245 | // console.log(hexdump(this.context.x9)); 246 | }, 247 | onLeave: function (retval) { 248 | } 249 | }) 250 | } 251 | ``` 252 | 253 | 最后: 254 | 255 | ```python 256 | import base64 257 | xordata = [0xd1,0x5a,0x6,0x90,0x44,0xe6,0xc7,0xe5,0xde,0x28,0xf7,0xf2,0x66,0x91,0xc8,0x85,0x42,0xdf,0xf9,0xe0,0x82,0x1,0x2b,0x3b,0x38,0x63,0x37,0xbd,0x2e,0x4d] 258 | data = base64.b64decode('5Gh2/y6Poq2/WIeLJfmh6yesnK7ndnJeWREFjRx8'.encode()) 259 | flag = bytes([xordata[i] ^ data[i] for i in range(len(xordata))]).decode() 260 | print(flag) 261 | ``` 262 | 263 | 264 | 265 | ## 1.2 Keypatch硬改算法逻辑 266 | 267 | ``` 268 | while ( *(unsigned __int8 *)(v12 + v24) == *((unsigned __int8 *)&v29 + v24) ) 269 | { 270 | if ( *(_BYTE *)(v12 + v24) ) 271 | { 272 | if ( ++v24 != 41 ) 273 | continue; 274 | } 275 | v28 = 1; 276 | goto LABEL_9; 277 | } 278 | v28 = 0; 279 | LABEL_9: 280 | result = free(); 281 | } 282 | else 283 | { 284 | v28 = 0; 285 | } 286 | if ( *(_QWORD *)(v3 + 40) == v43 ) 287 | result = v28; 288 | return result; 289 | ``` 290 | 291 | 使用Keypatch让v28等于1,输入任何都能成功。点击v28,显示其寄存器为w19,tab切换汇编。 292 | 293 | ![](pic/09.a.png) 294 | 295 | 选中w19,edit -> plugins -> keypunch patcher ,让w19 一直等于1,然后apply patches to input file 全局替换。 296 | 297 | 替换源so文件就可以了。 298 | 299 | ![](pic/10.a.png) 300 | 301 | 302 | 303 | ## 1.3 参考链接 304 | 305 | https://www.jianshu.com/p/d2d28920940c 306 | 307 | https://blog.csdn.net/hbhgyu/article/details/81321923 308 | 309 | https://www.52pojie.cn/thread-1369661-1-1.html 310 | 311 | https://www.52pojie.cn/thread-1378761-1-1.html 312 | 313 | https://www.52pojie.cn/thread-1383999-1-1.html 314 | 315 | -------------------------------------------------------------------------------- /FRIDA/B05/check.txt: -------------------------------------------------------------------------------- 1 | __int64 __fastcall Java_cn_pojie52_cm01_MainActivity_check(__int64 a1, __int64 a2, __int64 a3) 2 | { 3 | unsigned __int64 v3; // x22 4 | __int64 v4; // x19 5 | __int64 v5; // x20 6 | __int64 result; // x0 7 | __int64 v7; // x21 8 | __int64 v8; // x0 9 | __int64 v9; // x0 10 | __int64 v10; // x0 11 | __int64 v11; // x0 12 | int8x16_t v12; // q0 13 | int8x16_t v13; // q4 14 | int8x16_t v14; // q2 15 | int8x16_t v15; // q5 16 | int8x16_t v16; // q1 17 | unsigned int v17; // w10 18 | unsigned int v18; // w10 19 | int8x16_t v19; // q0 20 | unsigned int v20; // w10 21 | unsigned int v21; // w10 22 | unsigned int v22; // w10 23 | __int64 v23; // x8 24 | unsigned int v24; // w10 25 | unsigned int v25; // w10 26 | unsigned int v26; // w10 27 | unsigned int v27; // w19 28 | __int128 v28; // [xsp+0h] [xbp-A0h] 29 | __int128 v29; // [xsp+10h] [xbp-90h] 30 | char v30; // [xsp+21h] [xbp-7Fh] 31 | unsigned __int8 v31; // [xsp+22h] [xbp-7Eh] 32 | unsigned __int8 v32; // [xsp+23h] [xbp-7Dh] 33 | unsigned __int8 v33; // [xsp+24h] [xbp-7Ch] 34 | char v34; // [xsp+25h] [xbp-7Bh] 35 | unsigned __int8 v35; // [xsp+26h] [xbp-7Ah] 36 | char v36; // [xsp+27h] [xbp-79h] 37 | char v37; // [xsp+28h] [xbp-78h] 38 | __int128 v38; // [xsp+38h] [xbp-68h] 39 | __int128 v39; // [xsp+48h] [xbp-58h] 40 | __int128 v40; // [xsp+58h] [xbp-48h] 41 | __int128 v41; // [xsp+68h] [xbp-38h] 42 | __int64 v42; // [xsp+78h] [xbp-28h] 43 | 44 | v3 = _ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)); 45 | v4 = a1; 46 | v5 = a3; 47 | v42 = *(_QWORD *)(v3 + 40); 48 | result = (*(__int64 (**)(void))(*(_QWORD *)a1 + 1344LL))(); 49 | if ( (_DWORD)result == 30 ) 50 | { 51 | v7 = (*(__int64 (__fastcall **)(__int64, __int64, _QWORD))(*(_QWORD *)v4 + 1352LL))(v4, v5, 0LL); 52 | v41 = 0u; 53 | v40 = 0u; 54 | v39 = 0u; 55 | v38 = 0u; 56 | v8 = ((__int64 (*)(void))strlen)(); 57 | strncpy(&v38, v7, v8); 58 | (*(void (__fastcall **)(__int64, __int64, __int64))(*(_QWORD *)v4 + 1360LL))(v4, v5, v7); 59 | v9 = strlen(&v38); 60 | sub_B90(&v38, v9, "areyousure??????"); 61 | v10 = strlen(&v38); 62 | v11 = sub_D90(&v38, v10); 63 | v28 = unk_11A1; 64 | v29 = unk_11B1; 65 | *(__int128 *)((char *)&v29 + 9) = unk_11BA; 66 | v12.n128_u64[0] = -5570193308531903822LL; 67 | v12.n128_u64[1] = -5570193308531903822LL; 68 | v13.n128_u64[0] = -72340172838076674LL; 69 | v13.n128_u64[1] = -72340172838076674LL; 70 | LOBYTE(v28) = 53; 71 | v14 = veorq_s8( 72 | vaddq_s8( 73 | veorq_s8(vaddq_s8(*(int8x16_t *)((char *)&v28 + 1), v12), (int8x16_t)xmmword_1130), 74 | (int8x16_t)xmmword_1140), 75 | v13); 76 | v15.n128_u64[0] = 72340172838076673LL; 77 | v15.n128_u64[1] = 72340172838076673LL; 78 | v16.n128_u64[0] = 4485090715960753726LL; 79 | v16.n128_u64[1] = 4485090715960753726LL; 80 | *(__int128 *)((char *)&v28 + 1) = (__int128)vaddq_s8( 81 | veorq_s8( 82 | vsubq_s8( 83 | v15, 84 | vorrq_s8(vshrq_n_u8(v14, 7uLL), vshlq_n_s8(v14, 1uLL))), 85 | (int8x16_t)xmmword_1150), 86 | v16); 87 | v17 = (((unk_11C2 - 78) ^ 0xFFFFFFB6) - 113) ^ 0xFFFFFFFE; 88 | v30 = ((1 - (2 * v17 & 0xFE | (v17 >> 7) & 1)) ^ 0x21) + 62; 89 | v18 = (((v31 - 78) ^ 0xFFFFFFB5) - 114) ^ 0xFFFFFFFE; 90 | v31 = ((1 - (2 * v18 & 0xFE | (v18 >> 7) & 1)) ^ 0x22) + 62; 91 | v19 = veorq_s8( 92 | vaddq_s8( 93 | veorq_s8(vaddq_s8(*(int8x16_t *)((char *)&v29 + 1), v12), (int8x16_t)xmmword_1160), 94 | (int8x16_t)xmmword_1170), 95 | v13); 96 | v20 = (((v32 - 78) ^ 0xFFFFFFB4) - 115) ^ 0xFFFFFFFE; 97 | v32 = ((1 - (2 * v20 & 0xFE | (v20 >> 7) & 1)) ^ 0x23) + 62; 98 | v21 = (((v33 - 78) ^ 0xFFFFFFB3) - 116) ^ 0xFFFFFFFE; 99 | v33 = ((1 - (2 * v21 & 0xFE | (v21 >> 7) & 1)) ^ 0x24) + 62; 100 | v22 = (((unk_11C6 - 78) ^ 0xFFFFFFB2) - 117) ^ 0xFFFFFFFE; 101 | v34 = ((1 - (2 * v22 & 0xFE | (v22 >> 7) & 1)) ^ 0x25) + 62; 102 | v23 = 0LL; 103 | v24 = (((v35 - 78) ^ 0xFFFFFFB1) - 118) ^ 0xFFFFFFFE; 104 | v35 = ((1 - (2 * v24 & 0xFE | (v24 >> 7) & 1)) ^ 0x26) + 62; 105 | *(__int128 *)((char *)&v29 + 1) = (__int128)vaddq_s8( 106 | veorq_s8( 107 | vsubq_s8( 108 | v15, 109 | vorrq_s8(vshrq_n_u8(v19, 7uLL), vshlq_n_s8(v19, 1uLL))), 110 | (int8x16_t)xmmword_1180), 111 | v16); 112 | v25 = (((unk_11C8 - 78) ^ 0xFFFFFFB0) - 119) ^ 0xFFFFFFFE; 113 | v36 = ((1 - (2 * v25 & 0xFE | (v25 >> 7) & 1)) ^ 0x27) + 62; 114 | v26 = (((unk_11C9 - 78) ^ 0xFFFFFFBF) - 120) ^ 0xFFFFFFFE; 115 | v37 = ((1 - (2 * v26 & 0xFE | (v26 >> 7) & 1)) ^ 0x28) + 62; 116 | while ( *(unsigned __int8 *)(v11 + v23) == *((unsigned __int8 *)&v28 + v23) ) 117 | { 118 | if ( *(_BYTE *)(v11 + v23) ) 119 | { 120 | if ( ++v23 != 41 ) 121 | continue; 122 | } 123 | v27 = 1; 124 | goto LABEL_9; 125 | } 126 | v27 = 0; 127 | LABEL_9: 128 | result = free(); 129 | } 130 | else 131 | { 132 | v27 = 1; 133 | } 134 | if ( *(_QWORD *)(v3 + 40) == v42 ) 135 | result = v27; 136 | return result; 137 | } 138 | -------------------------------------------------------------------------------- /FRIDA/B05/pic/01.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/B05/pic/01.a.png -------------------------------------------------------------------------------- /FRIDA/B05/pic/02.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/B05/pic/02.a.png -------------------------------------------------------------------------------- /FRIDA/B05/pic/03.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/B05/pic/03.a.png -------------------------------------------------------------------------------- /FRIDA/B05/pic/04.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/B05/pic/04.a.png -------------------------------------------------------------------------------- /FRIDA/B05/pic/05.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/B05/pic/05.a.png -------------------------------------------------------------------------------- /FRIDA/B05/pic/06.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/B05/pic/06.a.png -------------------------------------------------------------------------------- /FRIDA/B05/pic/07.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/B05/pic/07.a.png -------------------------------------------------------------------------------- /FRIDA/B05/pic/08.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/B05/pic/08.a.png -------------------------------------------------------------------------------- /FRIDA/B05/pic/09.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/B05/pic/09.a.png -------------------------------------------------------------------------------- /FRIDA/B05/pic/10.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/FRIDA/B05/pic/10.a.png -------------------------------------------------------------------------------- /FRIDA/B05/sub_B90.txt: -------------------------------------------------------------------------------- 1 | unsigned __int64 __fastcall sub_B90(_BYTE *a1, unsigned int a2, __int64 a3) 2 | { 3 | unsigned __int64 v3; // x22 4 | _BYTE *v4; // x19 5 | __int64 v5; // x21 6 | unsigned int v6; // w20 7 | unsigned __int64 result; // x0 8 | unsigned __int64 v8; // x8 9 | signed int v9; // w9 10 | int v10; // w11 11 | int v11; // w9 12 | int v12; // w12 13 | signed int v13; // w9 14 | signed int v14; // w11 15 | __int64 v15; // x8 16 | int v16; // w12 17 | int v17; // w9 18 | int v18; // w13 19 | int v19; // w11 20 | int v20; // w14 21 | __int128 v21; // [xsp+0h] [xbp-140h] 22 | __int128 v22; // [xsp+10h] [xbp-130h] 23 | __int128 v23; // [xsp+20h] [xbp-120h] 24 | __int128 v24; // [xsp+30h] [xbp-110h] 25 | __int128 v25; // [xsp+40h] [xbp-100h] 26 | __int128 v26; // [xsp+50h] [xbp-F0h] 27 | __int128 v27; // [xsp+60h] [xbp-E0h] 28 | __int128 v28; // [xsp+70h] [xbp-D0h] 29 | __int128 v29; // [xsp+80h] [xbp-C0h] 30 | __int128 v30; // [xsp+90h] [xbp-B0h] 31 | __int128 v31; // [xsp+A0h] [xbp-A0h] 32 | __int128 v32; // [xsp+B0h] [xbp-90h] 33 | __int128 v33; // [xsp+C0h] [xbp-80h] 34 | __int128 v34; // [xsp+D0h] [xbp-70h] 35 | __int128 v35; // [xsp+E0h] [xbp-60h] 36 | __int128 v36; // [xsp+F0h] [xbp-50h] 37 | __int64 v37; // [xsp+108h] [xbp-38h] 38 | 39 | v3 = _ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)); 40 | v4 = a1; 41 | v5 = a3; 42 | v6 = a2; 43 | v37 = *(_QWORD *)(v3 + 40); 44 | result = strlen(a3); 45 | v21 = xmmword_11D0; 46 | v22 = xmmword_11E0; 47 | v23 = xmmword_11F0; 48 | v24 = xmmword_1200; 49 | v25 = xmmword_1210; 50 | v26 = xmmword_1220; 51 | v27 = xmmword_1230; 52 | v28 = xmmword_1240; 53 | v29 = xmmword_1250; 54 | v30 = xmmword_1260; 55 | v31 = xmmword_1270; 56 | v32 = xmmword_1280; 57 | v8 = 0LL; 58 | v9 = 0; 59 | v33 = xmmword_1290; 60 | v34 = xmmword_12A0; 61 | v35 = xmmword_12B0; 62 | v36 = xmmword_12C0; 63 | do 64 | { 65 | v10 = *((unsigned __int8 *)&v21 + v8); 66 | v11 = v9 + v10 + *(unsigned __int8 *)(v5 + v8 - v8 / result * result); 67 | v12 = v11 + 255; 68 | if ( v11 >= 0 ) 69 | v12 = v11; 70 | v9 = v11 - (v12 & 0xFFFFFF00); 71 | *((_BYTE *)&v21 + v8++) = *((_BYTE *)&v21 + v9); 72 | *((_BYTE *)&v21 + v9) = v10; 73 | } 74 | while ( v8 != 256 ); 75 | if ( v6 ) 76 | { 77 | v13 = 0; 78 | v14 = 0; 79 | v15 = v6; 80 | do 81 | { 82 | v16 = v13 + 1; 83 | if ( v13 + 1 >= 0 ) 84 | v17 = v13 + 1; 85 | else 86 | v17 = v13 + 256; 87 | v13 = v16 - (v17 & 0xFFFFFF00); 88 | v18 = *((unsigned __int8 *)&v21 + v13); 89 | v19 = v14 + v18; 90 | v20 = v19 + 255; 91 | if ( v19 >= 0 ) 92 | v20 = v19; 93 | v14 = v19 - (v20 & 0xFFFFFF00); 94 | --v15; 95 | *((_BYTE *)&v21 + v13) = *((_BYTE *)&v21 + v14); 96 | *((_BYTE *)&v21 + v14) = v18; 97 | *v4++ ^= *((_BYTE *)&v21 + (unsigned __int8)(*((_BYTE *)&v21 + v13) + v18)); 98 | } 99 | while ( v15 ); 100 | } 101 | *(_QWORD *)(v3 + 40); 102 | return result; 103 | } 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AndroidReverseStudy 2 | 安卓逆向学习 3 | 4 | 如有帮助 给个Star丫 5 | 6 | --- 7 | 8 | # 《FRIDA系列》 9 | ## A.配置与使用 10 | - [01.FRIDA](FRIDA/A01/README.md) 11 | - [02.Objection](FRIDA/A02/README.md) 12 | - [03.Tips](FRIDA/A03/README.md) 13 | 14 | ## B.FRIDA API篇 15 | - [01.Hook](FRIDA/B01/README.md) 16 | - [02.rpc、Process、Module、Memory使用方法及示例](FRIDA/B02/README.md) 17 | - [03.Interceptor、NativePointer(Function/Callback)使用方法及示例](FRIDA/B03/README.md) 18 | - [04.Native Hook 实例讲解](FRIDA/B04/README.md) 19 | - [05.Frida + IDA逆向app](FRIDA/B05/README.md) 20 | 21 | --- 22 | 23 | # 《逆向工具系列》 24 | ## A.Xposed篇 25 | - [01.Xposed配置](https://www.freebuf.com/articles/terminal/189021.html) 26 | - [02.Xposed API 实例讲解](Tool/XPOSED/A01/README.md) 27 | - [03.刷入官方Xposed](https://mp.weixin.qq.com/s/c97zoTxRrEeYLvD8YwIUVQ) 28 | - [04.Xposed魔改](https://mp.weixin.qq.com/s/YAMCrQSi0LFJGNIwB9qHDA) 29 | 30 | ## B.IDA篇 31 | 32 | - [01.IDA常用快捷键](Tool/IDA/A01/README.md) 33 | - [02.IDA修改硬编码过Frida反调试](Tool/IDA/A02/README.md) 34 | 35 | ## C.Unidbg篇 36 | 37 | - [01.Unidbg-基础配置](Tool/Unidbg/A01/README.md) 38 | - [02.Unidbg-奇技淫巧](Tool/Unidbg/A02/README.md) 39 | - [03.Unidbg-补环境](Tool/Unidbg/A03/README.md) 40 | 41 | --- 42 | 43 | # 《ANDROID开发系列》 44 | ## A.Native基础 45 | - [01.NDK入门开发](Android/A01/README.md) 46 | - [02.JNIEnv与反射](Android/A02/README.md) 47 | - [03.安卓so基本动态调试](Android/A03/README.md) 48 | - [04.安卓so每种哈希函数的特征](Android/A04/README.md) 49 | - [05.对称加密之DES](Android/A05/README.md) 50 | - [06.对称加密之AES](Android/A06/README.md) 51 | 52 | ## B.安卓源码编译 53 | - [01.AOSP源码编译7.1.2_r8](Android/B01/README.md) 54 | - [02.AOSP源码修改-制作简易沙箱](Android/B02/README.md) 55 | - [03.AOSP源码修改-自制沙箱进行无感知抓包](Android/B03/README.md) 56 | - [04.刷机](Android/B04/README.md) 57 | 58 | ## C.Arm汇编学习 59 | 60 | - [01.环境搭建](Android/C01/README.md) 61 | - [02.寄存器和指令基本格式](Android/C02/README.md) 62 | - [03.基本运算](Android/C03/README.md) 63 | 64 | ---- 65 | 66 | `致谢` 67 | 68 | 以上内容完全来自`r0ysue`以及`龙哥`的知识星球 69 | 70 | planet 71 | 72 | planet 73 | -------------------------------------------------------------------------------- /Tool/IDA/A01/README.md: -------------------------------------------------------------------------------- 1 | ### 1.1 IDA常用快捷键及技巧 2 | 3 | - shift + F12:查看so文件中所有常量字符串的值 4 | 5 | - tab键:汇编和伪 C 代码之间相互切换 6 | 7 | - / 键:添加注释 8 | 9 | - N 键:变量重命名 10 | 11 | - X 键:查看某变量的所有引用 12 | 13 | - H键:常量改成16进制(便于去查看是否于加密算法的初始化链接变量一致) 14 | 15 | - = 键:消除冗余的中间变量 16 | 17 | > 由于 IDA 反编译出来总是会有很多冗余的中间变量,如:v2 = v1; result = encrypt(v2); 选中 v2,按键盘上的 = 键,再点击 OK,即可消除中间变量 v2,result = encrypt(v1) 18 | 19 | - 在汇编查看图谱引用: 汇编代码 xrefs graph from 20 | 21 | - Options -> General -> Number of opcode bytes -> 4/8 22 | 23 | > 用于查看他是thumb(2\*8)还是arm(4\*8)。thumb在hook的时候地址就需要加1 24 | 25 | - c代码函数右击 出现fource call type :IDA识别的不准确,一般在jni函数上用,就是把函数的参数修正了,让函数变正常; 26 | 27 | - 动态调试时按`crtl+s`调出so表,选择想调试的(其中有多个的话选择带x权限的)。 28 | 29 | - ida c变量星花类型代表的是指针, hook 前面加ptr 30 | 31 | - search -> Immediate value 去搜索特征,进而去查看是否匹配出关键算法 32 | 33 | - 当某函数不能转换为伪代码时,全是DCB等,选中那串代码按C,然后按P转成函数,然后可以F5转换为伪代码了。 34 | 35 | > 按`c`把数据转为代码,按P是强转为函数, 这样才能用F5强转为伪代码 36 | 37 | ![](pic/01.a.png) 38 | 39 | 40 | 41 | ![](pic/01.b.png) 42 | 43 | ​ 直接按p转换成函数,bl是执行函数的意思。直接点loc7174 继续分析。 44 | 45 | - 当跳到ida某地址全部飘红时 46 | 47 | ![](pic/04.a.png) 48 | 49 | IDA 无法确认函数的起始地址和终止地址,必须人为选定一个指令范围,然后按P强制转成函数。可以发现,IDA识别出了函数的起始点,但把握不住函数的终点.我们顺着飘红往下拉: 50 | 51 | ![](pic/04.b.png) 52 | 53 | 3D9C比较像函数的结尾,我们尝试一下,从3B40开始从上往下拖拽,一直覆盖选中到3D9C,按P 54 | 55 | ![](pic/04.c.png) 56 | 57 | ![](pic/04.d.png) 58 | 59 | 现在已经被识别成了函数,F5看效果 60 | 61 | ![](pic/04.e.png) 62 | 63 | JUMPOUT真刺眼,看一下0x3C04这个位置怎么了 64 | 65 | ![](pic/04.f.png) 66 | 67 | 0x3C04应该是代码段,但被误识别成了数据,选中这个区域 68 | 69 | ![](pic/04.g.png) 70 | 71 | 按C 转成code 72 | 73 | ![](pic/04.h.png) 74 | 75 | ![](pic/04.i.png) 76 | 77 | 将先前的反编译结果界面关掉,按F5 再次反编译,就可以了。 78 | 79 | - 判断是Thumb还是Arm模式: 80 | 81 | > 1. 2 * 8 = 16、4 * 8 = 32。ARM模式指令总是4字节长度,Thumb指令长度多数为2字节,少部分指令是4字节。 82 | > 83 | > 2. IDA顶部选项框:Options-General 84 | > 85 | > ![](pic/01.c.png) 86 | > 87 | > 查看汇编指令的机器码: 88 | > 89 | > ![01.d](pic/01.d.png) 90 | > 91 | > 此处指令大多为两个字节长度,那就是Thumb。找准一行汇编,Alt+G快捷键。 92 | > 93 | > ![](pic/01.e.png) 94 | > 95 | > Thumb模式是1,ARM模式是0。除此之外,如果偶尔IDA反汇编出了问题,可以考虑它识别错了模式,需要Alt+G手动修改,调整模式。 96 | 97 | 98 | 99 | ### 1.2 IDA常用插件 100 | 101 | 搜索加密算法 102 | 103 | > findcrypt(静态识别率低)、IDASignsrch(静态识别率低)、findhash、IDAscope 104 | 105 | 插件编写 106 | 107 | > IPYIDA 108 | 109 | 110 | 111 | ### 1.3 导入结构体 112 | 113 | 未导入结构体时: 114 | 115 | ![](pic/02.a.png) 116 | 117 | 此算法显而易见为sha1算法,直接面向谷歌搜索`sha1Reset` ,得到代码: 118 | 119 | ```c 120 | void SHA1Reset(SHA1Context *context) 121 | { 122 | context->Length_Low = 0; 123 | context->Length_High = 0; 124 | context->Message_Block_Index = 0; 125 | 126 | context->Message_Digest[0] = 0x67452301; 127 | context->Message_Digest[1] = 0xEFCDAB89; 128 | context->Message_Digest[2] = 0x98BADCFE; 129 | context->Message_Digest[3] = 0x10325476; 130 | context->Message_Digest[4] = 0xC3D2E1F0; 131 | 132 | context->Computed = 0; 133 | context->Corrupted = 0; 134 | } 135 | ``` 136 | 137 | 继续搜一下SHA1Context的结构体,导入到ida中: 138 | 139 | ```c 140 | 141 | typedef struct SHA1Context 142 | { 143 | unsigned Message_Digest[5]; /* Message Digest (output) */ 144 | 145 | unsigned Length_Low; /* Message length in bits */ 146 | unsigned Length_High; /* Message length in bits */ 147 | 148 | unsigned char Message_Block[64]; /* 512-bit message blocks */ 149 | int Message_Block_Index; /* Index into message block array */ 150 | 151 | int Computed; /* Is the digest computed? */ 152 | int Corrupted; /* Is the message digest corruped? */ 153 | 154 | } SHA1Context; 155 | ``` 156 | 157 | 选中参数类型`int`右键点击`convert to struct *`,可以看到里面没有我们想转换的,需要手动导入,编辑添加到ida环境里。 158 | 159 | view -> open subviews -> local types -> 空白点击insert。 160 | 161 | 导入之后选中参数类型右键点击 convert to struct 选择你刚插入的结构体。效果如下,可以看到和源码没有什么差别。 162 | 163 | ![](pic/02.b.png) 164 | 165 | 或者选中变量右键`set lvar type`声明结构体。 166 | 167 | ![](pic/03.a.png) 168 | 169 | ![](pic/03.b.png) 170 | 171 | ![](pic/03.c.png) 172 | 173 | ![](pic/03.d.png) 174 | 175 | ![](pic/03.e.png) 176 | 177 | 结果如下: 178 | 179 | ![](pic/03.f.png) 180 | 181 | 有时候结构体导入存在依赖关系导入失败,比如想导入evp_md_ctx_st,但是它和evp_md_st存在着依赖关系,这就需要导入头文件openssl.h,如jni.h一样导入进去,file -> load file -> Parse C header file。 182 | 183 | ![](pic/02.c.png) 184 | 185 | 186 | 187 | ### 1.4 参考链接 188 | 189 | https://blog.csdn.net/wuchuanpingstone/article/details/78094363 190 | -------------------------------------------------------------------------------- /Tool/IDA/A01/pic/01.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/pic/01.a.png -------------------------------------------------------------------------------- /Tool/IDA/A01/pic/01.b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/pic/01.b.png -------------------------------------------------------------------------------- /Tool/IDA/A01/pic/01.c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/pic/01.c.png -------------------------------------------------------------------------------- /Tool/IDA/A01/pic/01.d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/pic/01.d.png -------------------------------------------------------------------------------- /Tool/IDA/A01/pic/01.e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/pic/01.e.png -------------------------------------------------------------------------------- /Tool/IDA/A01/pic/02.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/pic/02.a.png -------------------------------------------------------------------------------- /Tool/IDA/A01/pic/02.b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/pic/02.b.png -------------------------------------------------------------------------------- /Tool/IDA/A01/pic/02.c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/pic/02.c.png -------------------------------------------------------------------------------- /Tool/IDA/A01/pic/03.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/pic/03.a.png -------------------------------------------------------------------------------- /Tool/IDA/A01/pic/03.b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/pic/03.b.png -------------------------------------------------------------------------------- /Tool/IDA/A01/pic/03.c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/pic/03.c.png -------------------------------------------------------------------------------- /Tool/IDA/A01/pic/03.d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/pic/03.d.png -------------------------------------------------------------------------------- /Tool/IDA/A01/pic/03.e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/pic/03.e.png -------------------------------------------------------------------------------- /Tool/IDA/A01/pic/03.f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/pic/03.f.png -------------------------------------------------------------------------------- /Tool/IDA/A01/pic/04.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/pic/04.a.png -------------------------------------------------------------------------------- /Tool/IDA/A01/pic/04.b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/pic/04.b.png -------------------------------------------------------------------------------- /Tool/IDA/A01/pic/04.c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/pic/04.c.png -------------------------------------------------------------------------------- /Tool/IDA/A01/pic/04.d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/pic/04.d.png -------------------------------------------------------------------------------- /Tool/IDA/A01/pic/04.e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/pic/04.e.png -------------------------------------------------------------------------------- /Tool/IDA/A01/pic/04.f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/pic/04.f.png -------------------------------------------------------------------------------- /Tool/IDA/A01/pic/04.g.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/pic/04.g.png -------------------------------------------------------------------------------- /Tool/IDA/A01/pic/04.h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/pic/04.h.png -------------------------------------------------------------------------------- /Tool/IDA/A01/pic/04.i.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/pic/04.i.png -------------------------------------------------------------------------------- /Tool/IDA/A01/内容/代码和使用到的文件/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define MD5_LONG unsigned long 5 | // 分组大小 6 | #define MD5_CBLOCK 64 7 | // 分块个数 8 | #define MD5_LBLOCK (MD5_CBLOCK/4) 9 | // 摘要长度(字节) 10 | #define MD5_DIGEST_LENGTH 16 11 | 12 | #define MD32_REG_T long 13 | #define DATA_ORDER_IS_LITTLE_ENDIAN 14 | 15 | // 四个初始化常量 16 | #define INIT_DATA_A (unsigned long)0x67452301L 17 | #define INIT_DATA_B (unsigned long)0xefcdab89L 18 | #define INIT_DATA_C (unsigned long)0x98badcfeL 19 | #define INIT_DATA_D (unsigned long)0x10325476L 20 | 21 | // 循环左移以及取低64位 22 | #define ROTATE(a,n) (((a)<<(n))|(((a)&0xffffffff)>>(32-(n)))) 23 | 24 | // 大小端序互转 25 | #define HOST_c2l(c,l) (l =(((unsigned long)(*((c)++))) ), \ 26 | l|=(((unsigned long)(*((c)++)))<< 8), \ 27 | l|=(((unsigned long)(*((c)++)))<<16), \ 28 | l|=(((unsigned long)(*((c)++)))<<24) ) 29 | 30 | #define HOST_l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \ 31 | *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ 32 | *((c)++)=(unsigned char)(((l)>>16)&0xff), \ 33 | *((c)++)=(unsigned char)(((l)>>24)&0xff), \ 34 | l) 35 | 36 | // 更新链接变量值 37 | #define HASH_MAKE_STRING(c,s) do { \ 38 | unsigned long ll; \ 39 | ll=(c)->A; (void)HOST_l2c(ll,(s)); \ 40 | ll=(c)->B; (void)HOST_l2c(ll,(s)); \ 41 | ll=(c)->C; (void)HOST_l2c(ll,(s)); \ 42 | ll=(c)->D; (void)HOST_l2c(ll,(s)); \ 43 | } while (0) 44 | 45 | // 四个初始化非线性函数,或者叫逻辑函数 46 | #define F(b,c,d) ((((c) ^ (d)) & (b)) ^ (d)) 47 | #define G(b,c,d) ((((b) ^ (c)) & (d)) ^ (c)) 48 | #define H(b,c,d) ((b) ^ (c) ^ (d)) 49 | #define I(b,c,d) (((~(d)) | (b)) ^ (c)) 50 | 51 | // F函数,每隔16步/轮 换下一个 52 | #define R0(a,b,c,d,k,s,t) { \ 53 | a+=((k)+(t)+F((b),(c),(d))); \ 54 | a=ROTATE(a,s); \ 55 | a+=b; }; 56 | 57 | #define R1(a,b,c,d,k,s,t) { \ 58 | a+=((k)+(t)+G((b),(c),(d))); \ 59 | a=ROTATE(a,s); \ 60 | a+=b;}; 61 | 62 | #define R2(a,b,c,d,k,s,t) { \ 63 | a+=((k)+(t)+H((b),(c),(d))); \ 64 | a=ROTATE(a,s); \ 65 | a+=b; }; 66 | 67 | #define R3(a,b,c,d,k,s,t) { \ 68 | a+=((k)+(t)+I((b),(c),(d))); \ 69 | a=ROTATE(a,s); \ 70 | a+=b; }; 71 | 72 | typedef struct MD5state_st1{ 73 | MD5_LONG A,B,C,D; // ABCD 74 | MD5_LONG Nl,Nh; // 数据的bit数计数器(对2^64取余),Nh存储高32位,Nl存储低32位。这种设计是服务于32位处理器,MD5的设计就是为了服务于32位处理器的。 75 | MD5_LONG data[MD5_LBLOCK];//数据缓冲区 76 | unsigned int num; 77 | }MD5_CTX; // 存放MD5算法相关信息的结构体定义 78 | 79 | unsigned char cleanse_ctr = 0; 80 | 81 | 82 | // 初始化链接变量/幻数 83 | int MD5_Init(MD5_CTX *c){ 84 | memset (c,0,sizeof(*c)); 85 | c->A=INIT_DATA_A; 86 | c->B=INIT_DATA_B; 87 | c->C=INIT_DATA_C; 88 | c->D=INIT_DATA_D; 89 | return 1; 90 | } 91 | 92 | // md5 一个分组中的全部运算 93 | void md5_block_data_order(MD5_CTX *c, const void *data_, size_t num){ 94 | const unsigned char *data=data_; 95 | register unsigned MD32_REG_T A,B,C,D,l; 96 | #ifndef MD32_XARRAY 97 | unsigned MD32_REG_T XX0, XX1, XX2, XX3, XX4, XX5, XX6, XX7, 98 | XX8, XX9,XX10,XX11,XX12,XX13,XX14,XX15; 99 | # define X(i) XX##i 100 | #else 101 | MD5_LONG XX[MD5_LBLOCK]; 102 | # define X(i) XX[i] 103 | #endif 104 | A=c->A; 105 | B=c->B; 106 | C=c->C; 107 | D=c->D; 108 | // 64轮 109 | // 前16轮需要改变分组中每个分块的 110 | for (;num--;){ 111 | HOST_c2l(data,l); X( 0)=l; HOST_c2l(data,l); X( 1)=l; 112 | /* Round 0 */ 113 | R0(A,B,C,D,X( 0), 7,0xd76aa478L); HOST_c2l(data,l); X( 2)=l; 114 | R0(D,A,B,C,X( 1),12,0xe8c7b756L); HOST_c2l(data,l); X( 3)=l; 115 | R0(C,D,A,B,X( 2),17,0x242070dbL); HOST_c2l(data,l); X( 4)=l; 116 | R0(B,C,D,A,X( 3),22,0xc1bdceeeL); HOST_c2l(data,l); X( 5)=l; 117 | R0(A,B,C,D,X( 4), 7,0xf57c0fafL); HOST_c2l(data,l); X( 6)=l; 118 | R0(D,A,B,C,X( 5),12,0x4787c62aL); HOST_c2l(data,l); X( 7)=l; 119 | R0(C,D,A,B,X( 6),17,0xa8304613L); HOST_c2l(data,l); X( 8)=l; 120 | R0(B,C,D,A,X( 7),22,0xfd469501L); HOST_c2l(data,l); X( 9)=l; 121 | R0(A,B,C,D,X( 8), 7,0x698098d8L); HOST_c2l(data,l); X(10)=l; 122 | R0(D,A,B,C,X( 9),12,0x8b44f7afL); HOST_c2l(data,l); X(11)=l; 123 | R0(C,D,A,B,X(10),17,0xffff5bb1L); HOST_c2l(data,l); X(12)=l; 124 | R0(B,C,D,A,X(11),22,0x895cd7beL); HOST_c2l(data,l); X(13)=l; 125 | R0(A,B,C,D,X(12), 7,0x6b901122L); HOST_c2l(data,l); X(14)=l; 126 | R0(D,A,B,C,X(13),12,0xfd987193L); HOST_c2l(data,l); X(15)=l; 127 | R0(C,D,A,B,X(14),17,0xa679438eL); 128 | R0(B,C,D,A,X(15),22,0x49b40821L); 129 | /* Round 1 */ 130 | R1(A,B,C,D,X( 1), 5,0xf61e2562L); 131 | R1(D,A,B,C,X( 6), 9,0xc040b340L); 132 | R1(C,D,A,B,X(11),14,0x265e5a51L); 133 | R1(B,C,D,A,X( 0),20,0xe9b6c7aaL); 134 | R1(A,B,C,D,X( 5), 5,0xd62f105dL); 135 | R1(D,A,B,C,X(10), 9,0x02441453L); 136 | R1(C,D,A,B,X(15),14,0xd8a1e681L); 137 | R1(B,C,D,A,X( 4),20,0xe7d3fbc8L); 138 | R1(A,B,C,D,X( 9), 5,0x21e1cde6L); 139 | R1(D,A,B,C,X(14), 9,0xc33707d6L); 140 | R1(C,D,A,B,X( 3),14,0xf4d50d87L); 141 | R1(B,C,D,A,X( 8),20,0x455a14edL); 142 | R1(A,B,C,D,X(13), 5,0xa9e3e905L); 143 | R1(D,A,B,C,X( 2), 9,0xfcefa3f8L); 144 | R1(C,D,A,B,X( 7),14,0x676f02d9L); 145 | R1(B,C,D,A,X(12),20,0x8d2a4c8aL); 146 | /* Round 2 */ 147 | R2(A,B,C,D,X( 5), 4,0xfffa3942L); 148 | R2(D,A,B,C,X( 8),11,0x8771f681L); 149 | R2(C,D,A,B,X(11),16,0x6d9d6122L); 150 | R2(B,C,D,A,X(14),23,0xfde5380cL); 151 | R2(A,B,C,D,X( 1), 4,0xa4beea44L); 152 | R2(D,A,B,C,X( 4),11,0x4bdecfa9L); 153 | R2(C,D,A,B,X( 7),16,0xf6bb4b60L); 154 | R2(B,C,D,A,X(10),23,0xbebfbc70L); 155 | R2(A,B,C,D,X(13), 4,0x289b7ec6L); 156 | R2(D,A,B,C,X( 0),11,0xeaa127faL); 157 | R2(C,D,A,B,X( 3),16,0xd4ef3085L); 158 | R2(B,C,D,A,X( 6),23,0x04881d05L); 159 | R2(A,B,C,D,X( 9), 4,0xd9d4d039L); 160 | R2(D,A,B,C,X(12),11,0xe6db99e5L); 161 | R2(C,D,A,B,X(15),16,0x1fa27cf8L); 162 | R2(B,C,D,A,X( 2),23,0xc4ac5665L); 163 | /* Round 3 */ 164 | R3(A,B,C,D,X( 0), 6,0xf4292244L); 165 | R3(D,A,B,C,X( 7),10,0x432aff97L); 166 | R3(C,D,A,B,X(14),15,0xab9423a7L); 167 | R3(B,C,D,A,X( 5),21,0xfc93a039L); 168 | R3(A,B,C,D,X(12), 6,0x655b59c3L); 169 | R3(D,A,B,C,X( 3),10,0x8f0ccc92L); 170 | R3(C,D,A,B,X(10),15,0xffeff47dL); 171 | R3(B,C,D,A,X( 1),21,0x85845dd1L); 172 | R3(A,B,C,D,X( 8), 6,0x6fa87e4fL); 173 | R3(D,A,B,C,X(15),10,0xfe2ce6e0L); 174 | R3(C,D,A,B,X( 6),15,0xa3014314L); 175 | R3(B,C,D,A,X(13),21,0x4e0811a1L); 176 | R3(A,B,C,D,X( 4), 6,0xf7537e82L); 177 | R3(D,A,B,C,X(11),10,0xbd3af235L); 178 | R3(C,D,A,B,X( 2),15,0x2ad7d2bbL); 179 | R3(B,C,D,A,X( 9),21,0xeb86d391L); 180 | 181 | A = c->A += A; 182 | B = c->B += B; 183 | C = c->C += C; 184 | D = c->D += D; 185 | } 186 | } 187 | 188 | // 传入需要哈希的明文,支持多次调用 189 | int MD5_Update(MD5_CTX *c, const void *data_, size_t len){ 190 | const unsigned char *data=data_; 191 | unsigned char *p; 192 | MD5_LONG l; 193 | size_t n; 194 | 195 | if (len==0) return 1; 196 | // 低位 197 | l=(c->Nl+(((MD5_LONG)len)<<3))&0xffffffffUL; 198 | if (l < c->Nl) 199 | c->Nh++; 200 | // 高位 201 | c->Nh+=(MD5_LONG)(len>>29); 202 | c->Nl=l; 203 | 204 | n = c->num; 205 | if (n != 0){ 206 | p=(unsigned char *)c->data; 207 | 208 | if (len >= MD5_CBLOCK || len+n >= MD5_CBLOCK){ 209 | memcpy (p+n,data,MD5_CBLOCK-n); 210 | md5_block_data_order(c,p,1); 211 | n = MD5_CBLOCK-n; 212 | data += n; 213 | len -= n; 214 | c->num = 0; 215 | memset (p,0,MD5_CBLOCK); 216 | }else{ 217 | memcpy (p+n,data,len); 218 | c->num += (unsigned int)len; 219 | return 1; 220 | } 221 | } 222 | 223 | n = len/MD5_CBLOCK; 224 | if (n > 0){ 225 | md5_block_data_order(c,data,n); 226 | n *= MD5_CBLOCK; 227 | data += n; 228 | len -= n; 229 | } 230 | 231 | if (len != 0){ 232 | p = (unsigned char *)c->data; 233 | c->num = (unsigned int)len; 234 | memcpy (p,data,len); 235 | } 236 | return 1; 237 | } 238 | 239 | // 得出最终结果 240 | int MD5_Final(unsigned char *md, MD5_CTX *c){ 241 | unsigned char *p = (unsigned char *)c->data; 242 | size_t n = c->num; 243 | 244 | p[n] = 0x80; /* there is always room for one */ 245 | n++; 246 | 247 | if (n > (MD5_CBLOCK-8)){ 248 | memset (p+n,0,MD5_CBLOCK-n); 249 | n=0; 250 | md5_block_data_order(c,p,1); 251 | } 252 | memset (p+n,0,MD5_CBLOCK-8-n); 253 | 254 | p += MD5_CBLOCK-8; 255 | #if defined(DATA_ORDER_IS_BIG_ENDIAN) 256 | (void)HOST_l2c(c->Nh,p); 257 | (void)HOST_l2c(c->Nl,p); 258 | #elif defined(DATA_ORDER_IS_LITTLE_ENDIAN) 259 | (void)HOST_l2c(c->Nl,p); 260 | (void)HOST_l2c(c->Nh,p); 261 | #endif 262 | p -= MD5_CBLOCK; 263 | md5_block_data_order(c,p,1); 264 | c->num=0; 265 | memset (p,0,MD5_CBLOCK); 266 | 267 | #ifndef HASH_MAKE_STRING 268 | #error "HASH_MAKE_STRING must be defined!" 269 | #else 270 | HASH_MAKE_STRING(c,md); 271 | #endif 272 | 273 | return 1; 274 | } 275 | 276 | //清除加载的各种算法,包括对称算法、摘要算法以及 PBE 算法,并清除这些算法相关的哈希表的内容。 277 | void OPENSSL_cleanse(void *ptr, size_t len){ 278 | unsigned char *p = ptr; 279 | size_t loop = len, ctr = cleanse_ctr; 280 | while(loop--){ 281 | *(p++) = (unsigned char)ctr; 282 | ctr += (17 + ((size_t)p & 0xF)); 283 | } 284 | p=memchr(ptr, (unsigned char)ctr, len); 285 | if(p) 286 | ctr += (63 + (size_t)p); 287 | cleanse_ctr = (unsigned char)ctr; 288 | } 289 | 290 | unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md){ 291 | MD5_CTX c; 292 | static unsigned char m[MD5_DIGEST_LENGTH]; 293 | 294 | if (md == NULL) md=m; 295 | // 初始化四个魔数 296 | if (!MD5_Init(&c)) 297 | return NULL; 298 | MD5_Update(&c,d,n); 299 | MD5_Final(md,&c); 300 | // 这一步是清除上下文,讲道理 301 | // 可有可无,是安全性上的考虑 302 | OPENSSL_cleanse(&c,sizeof(c)); 303 | return(md); 304 | } 305 | // update 多次涉及到md5的原理 306 | int main(){ 307 | 308 | // unsigned long a = 0xFF120000; 309 | // a += 0x1000000; 310 | unsigned char in[]="123456"; 311 | /*out = 55 ff 40 9e 85 05 61 0c 02 8a d5 d4 ff a5 ea f7*/ 312 | unsigned char out[16]; 313 | size_t n; 314 | int i; 315 | 316 | n = strlen((const char*)in); 317 | MD5(in,n,out); 318 | printf("\n\nMD5 digest result :\n"); 319 | for(i=0;i<16;i++) 320 | printf("%02x ",out[i]); 321 | printf("\n"); 322 | 323 | } -------------------------------------------------------------------------------- /Tool/IDA/A01/内容/代码和使用到的文件/md5_algorithm.py: -------------------------------------------------------------------------------- 1 | import binascii 2 | import sys 3 | import os.path 4 | 5 | SV = [0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 6 | 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 7 | 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 8 | 0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 9 | 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 10 | 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 11 | 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 12 | 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 13 | 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, 0xd9d4d039, 14 | 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244, 0x432aff97, 15 | 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 16 | 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 17 | 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391] 18 | 19 | 20 | # 根据ascil编码把字符转成对应的二进制 21 | def binvalue(val, bitsize): 22 | binval = bin(val)[2:] if isinstance(val, int) else bin(ord(val))[2:] 23 | if len(binval) > bitsize: 24 | raise ("binary value larger than the expected size") 25 | while len(binval) < bitsize: 26 | binval = "0" + binval 27 | return binval 28 | 29 | 30 | def string_to_bit_array(text): 31 | array = list() 32 | for char in text: 33 | binval = binvalue(char, 8) 34 | array.extend([int(x) for x in list(binval)]) 35 | return array 36 | 37 | 38 | # 循环左移 39 | def leftCircularShift(k, bits): 40 | bits = bits % 32 41 | k = k % (2 ** 32) 42 | upper = (k << bits) % (2 ** 32) 43 | result = upper | (k >> (32 - (bits))) 44 | return (result) 45 | 46 | 47 | # 分块 48 | def blockDivide(block, chunks): 49 | result = [] 50 | size = len(block) // chunks 51 | for i in range(0, chunks): 52 | result.append(int.from_bytes(block[i * size:(i + 1) * size], byteorder="little")) 53 | return result 54 | 55 | 56 | # F函数作用于“比特位”上 57 | # if x then y else z 58 | def F(X, Y, Z): 59 | return ((X & Y) | ((~X) & Z)) 60 | 61 | 62 | # if z then x else y 63 | def G(X, Y, Z): 64 | return ((X & Z) | (Y & (~Z))) 65 | 66 | 67 | # if X = Y then Z else ~Z 68 | def H(X, Y, Z): 69 | return (X ^ Y ^ Z) 70 | 71 | 72 | def I(X, Y, Z): 73 | return (Y ^ (X | (~Z))) 74 | 75 | 76 | # 四个F函数 77 | def FF(a, b, c, d, M, s, t): 78 | result = b + leftCircularShift((a + F(b, c, d) + M + t), s) 79 | return (result) 80 | 81 | 82 | def GG(a, b, c, d, M, s, t): 83 | result = b + leftCircularShift((a + G(b, c, d) + M + t), s) 84 | return (result) 85 | 86 | 87 | def HH(a, b, c, d, M, s, t): 88 | result = b + leftCircularShift((a + H(b, c, d) + M + t), s) 89 | return (result) 90 | 91 | 92 | def II(a, b, c, d, M, s, t): 93 | result = b + leftCircularShift((a + I(b, c, d) + M + t), s) 94 | return (result) 95 | 96 | 97 | # 数据转换 98 | def fmt8(num): 99 | bighex = "{0:08x}".format(num) 100 | binver = binascii.unhexlify(bighex) 101 | result = "{0:08x}".format(int.from_bytes(binver, byteorder='little')) 102 | return (result) 103 | 104 | 105 | # 计算比特长度 106 | def bitlen(bitstring): 107 | return len(bitstring) * 8 108 | 109 | 110 | def md5sum(msg): 111 | # 计算比特长度,如果内容过长,64个比特放不下。就取低64bit。 112 | msgLen = bitlen(msg) % (2 ** 64) 113 | # 先填充一个0x80,其实是先填充一个1,后面跟对应个数的0,因为一个明文的编码至少需要8比特,所以直接填充 0b10000000即0x80 114 | msg = msg + b'\x80' # 0x80 = 1000 0000 115 | # 似乎各种编码,即使是一个字母,都至少得1个字节,即8bit才能表示,所以不会出现原文55bit,pad1就满足的情况?可是不对呀,要是二进制文件呢? 116 | # 填充0到满足要求为止。 117 | zeroPad = (448 - (msgLen + 8) % 512) % 512 118 | zeroPad //= 8 119 | msg = msg + b'\x00' * zeroPad + msgLen.to_bytes(8, byteorder='little') 120 | # 计算循环轮数,512个为一轮 121 | msgLen = bitlen(msg) 122 | iterations = msgLen // 512 123 | # 初始化变量 124 | # 算法魔改的第一个点,也是最明显的点 125 | A = 0x67452301 126 | B = 0xefcdab89 127 | C = 0x98badcfe 128 | D = 0x10325476 129 | # MD5的主体就是对abcd进行n次的迭代,所以得有个初始值,可以随便选,也可以用默认的魔数,这个改起来毫无风险,所以大家爱魔改它,甚至改这个都不算魔改。 130 | # main loop 131 | for i in range(0, iterations): 132 | a = A 133 | b = B 134 | c = C 135 | d = D 136 | block = msg[i * 64:(i + 1) * 64] 137 | # 明文的处理,顺便调整了一下端序 138 | M = blockDivide(block, 16) 139 | # Rounds 140 | a = FF(a, b, c, d, M[0], 7, SV[0]) 141 | d = FF(d, a, b, c, M[1], 12, SV[1]) 142 | c = FF(c, d, a, b, M[2], 17, SV[2]) 143 | b = FF(b, c, d, a, M[3], 22, SV[3]) 144 | a = FF(a, b, c, d, M[4], 7, SV[4]) 145 | d = FF(d, a, b, c, M[5], 12, SV[5]) 146 | c = FF(c, d, a, b, M[6], 17, SV[6]) 147 | b = FF(b, c, d, a, M[7], 22, SV[7]) 148 | a = FF(a, b, c, d, M[8], 7, SV[8]) 149 | d = FF(d, a, b, c, M[9], 12, SV[9]) 150 | c = FF(c, d, a, b, M[10], 17, SV[10]) 151 | b = FF(b, c, d, a, M[11], 22, SV[11]) 152 | a = FF(a, b, c, d, M[12], 7, SV[12]) 153 | d = FF(d, a, b, c, M[13], 12, SV[13]) 154 | c = FF(c, d, a, b, M[14], 17, SV[14]) 155 | b = FF(b, c, d, a, M[15], 22, SV[15]) 156 | 157 | a = GG(a, b, c, d, M[1], 5, SV[16]) 158 | d = GG(d, a, b, c, M[6], 9, SV[17]) 159 | c = GG(c, d, a, b, M[11], 14, SV[18]) 160 | b = GG(b, c, d, a, M[0], 20, SV[19]) 161 | a = GG(a, b, c, d, M[5], 5, SV[20]) 162 | d = GG(d, a, b, c, M[10], 9, SV[21]) 163 | c = GG(c, d, a, b, M[15], 14, SV[22]) 164 | b = GG(b, c, d, a, M[4], 20, SV[23]) 165 | a = GG(a, b, c, d, M[9], 5, SV[24]) 166 | d = GG(d, a, b, c, M[14], 9, SV[25]) 167 | c = GG(c, d, a, b, M[3], 14, SV[26]) 168 | b = GG(b, c, d, a, M[8], 20, SV[27]) 169 | a = GG(a, b, c, d, M[13], 5, SV[28]) 170 | d = GG(d, a, b, c, M[2], 9, SV[29]) 171 | c = GG(c, d, a, b, M[7], 14, SV[30]) 172 | b = GG(b, c, d, a, M[12], 20, SV[31]) 173 | 174 | a = HH(a, b, c, d, M[5], 4, SV[32]) 175 | d = HH(d, a, b, c, M[8], 11, SV[33]) 176 | c = HH(c, d, a, b, M[11], 16, SV[34]) 177 | b = HH(b, c, d, a, M[14], 23, SV[35]) 178 | a = HH(a, b, c, d, M[1], 4, SV[36]) 179 | d = HH(d, a, b, c, M[4], 11, SV[37]) 180 | c = HH(c, d, a, b, M[7], 16, SV[38]) 181 | b = HH(b, c, d, a, M[10], 23, SV[39]) 182 | a = HH(a, b, c, d, M[13], 4, SV[40]) 183 | d = HH(d, a, b, c, M[0], 11, SV[41]) 184 | c = HH(c, d, a, b, M[3], 16, SV[42]) 185 | b = HH(b, c, d, a, M[6], 23, SV[43]) 186 | a = HH(a, b, c, d, M[9], 4, SV[44]) 187 | d = HH(d, a, b, c, M[12], 11, SV[45]) 188 | c = HH(c, d, a, b, M[15], 16, SV[46]) 189 | b = HH(b, c, d, a, M[2], 23, SV[47]) 190 | 191 | a = II(a, b, c, d, M[0], 6, SV[48]) 192 | d = II(d, a, b, c, M[7], 10, SV[49]) 193 | c = II(c, d, a, b, M[14], 15, SV[50]) 194 | b = II(b, c, d, a, M[5], 21, SV[51]) 195 | a = II(a, b, c, d, M[12], 6, SV[52]) 196 | d = II(d, a, b, c, M[3], 10, SV[53]) 197 | c = II(c, d, a, b, M[10], 15, SV[54]) 198 | b = II(b, c, d, a, M[1], 21, SV[55]) 199 | a = II(a, b, c, d, M[8], 6, SV[56]) 200 | d = II(d, a, b, c, M[15], 10, SV[57]) 201 | c = II(c, d, a, b, M[6], 15, SV[58]) 202 | b = II(b, c, d, a, M[13], 21, SV[59]) 203 | a = II(a, b, c, d, M[4], 6, SV[60]) 204 | d = II(d, a, b, c, M[11], 10, SV[61]) 205 | c = II(c, d, a, b, M[2], 15, SV[62]) 206 | b = II(b, c, d, a, M[9], 21, SV[63]) 207 | A = (A + a) % (2 ** 32) 208 | B = (B + b) % (2 ** 32) 209 | C = (C + c) % (2 ** 32) 210 | D = (D + d) % (2 ** 32) 211 | result = fmt8(A) + fmt8(B) + fmt8(C) + fmt8(D) 212 | return result 213 | 214 | 215 | if __name__ == "__main__": 216 | data = str("123456aaaaaaaaaaaa43444444444444444444444uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu22222222").encode("UTF-8") 217 | print("plainText: ", data) 218 | print("result: ", md5sum(data)) 219 | 220 | 221 | -------------------------------------------------------------------------------- /Tool/IDA/A01/内容/代码和使用到的文件/openssl.h: -------------------------------------------------------------------------------- 1 | struct evp_md_ctx_st; 2 | struct evp_md_st; 3 | typedef struct evp_md_ctx_st EVP_MD_CTX; 4 | typedef struct evp_md_st EVP_MD; 5 | 6 | struct evp_md_ctx_st { 7 | const evp_md_st *digest; 8 | int *engine; /* functional reference if 'digest' is 9 | * ENGINE-provided */ 10 | unsigned long flags; 11 | void *md_data; 12 | /* Public key context for sign/verify */ 13 | int *pctx; 14 | /* Update function: usually copied from EVP_MD */ 15 | int (*update) (EVP_MD_CTX *ctx, const void *data, size_t count); 16 | }EVP_MD_CTX; 17 | 18 | struct evp_md_st { 19 | int type; 20 | int md_size; 21 | unsigned long flags; 22 | int (*init) (EVP_MD_CTX *ctx); 23 | int (*update) (EVP_MD_CTX *ctx, const void *data, size_t count); 24 | int (*final) (EVP_MD_CTX *ctx, unsigned char *md); 25 | int (*copy) (EVP_MD_CTX *to, const EVP_MD_CTX *from); 26 | int (*cleanup) (EVP_MD_CTX *ctx); 27 | int block_size; 28 | int ctx_size; /* how big does the ctx->md_data need to be */ 29 | /* control function */ 30 | int (*md_ctrl) (EVP_MD_CTX *ctx, int cmd, int p1, void *p2); 31 | }EVP_MD; 32 | 33 | struct hmac_ctx_st 34 | { 35 | const EVP_MD *md; 36 | EVP_MD_CTX md_ctx; 37 | EVP_MD_CTX i_ctx; 38 | EVP_MD_CTX o_ctx; 39 | unsigned int key_length; 40 | unsigned char key[64]; 41 | } HMAC_CTX; 42 | -------------------------------------------------------------------------------- /Tool/IDA/A01/内容/样本/1.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/内容/样本/1.so -------------------------------------------------------------------------------- /Tool/IDA/A01/内容/样本/2.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/内容/样本/2.so -------------------------------------------------------------------------------- /Tool/IDA/A01/内容/样本/3.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/内容/样本/3.so -------------------------------------------------------------------------------- /Tool/IDA/A01/内容/样本/libcrypto.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/内容/样本/libcrypto.so -------------------------------------------------------------------------------- /Tool/IDA/A01/内容/样本/libkeyinfo.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/内容/样本/libkeyinfo.so -------------------------------------------------------------------------------- /Tool/IDA/A01/内容/样本/libmtguard.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/内容/样本/libmtguard.so -------------------------------------------------------------------------------- /Tool/IDA/A01/内容/样本/libmwnative-sign.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/内容/样本/libmwnative-sign.so -------------------------------------------------------------------------------- /Tool/IDA/A01/内容/样本/libnative-lib.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/内容/样本/libnative-lib.so -------------------------------------------------------------------------------- /Tool/IDA/A01/内容/资料/08960303.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/内容/资料/08960303.pdf -------------------------------------------------------------------------------- /Tool/IDA/A01/内容/资料/Automated_Identification_of_Cryptographic_Primitiv.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/内容/资料/Automated_Identification_of_Cryptographic_Primitiv.pdf -------------------------------------------------------------------------------- /Tool/IDA/A01/内容/资料/Automatic Detection of Cryptographic Algorithms.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/内容/资料/Automatic Detection of Cryptographic Algorithms.pdf -------------------------------------------------------------------------------- /Tool/IDA/A01/内容/资料/Cryptographic Algorithms Analysis Technology Research Based on Functions Signature Recognition.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/内容/资料/Cryptographic Algorithms Analysis Technology Research Based on Functions Signature Recognition.pdf -------------------------------------------------------------------------------- /Tool/IDA/A01/内容/资料/Detection and Analysis of Cryptographic Data.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/内容/资料/Detection and Analysis of Cryptographic Data.pdf -------------------------------------------------------------------------------- /Tool/IDA/A01/内容/资料/HES-2012-jcalvet-CryptoFunctionIdentification.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/内容/资料/HES-2012-jcalvet-CryptoFunctionIdentification.pdf -------------------------------------------------------------------------------- /Tool/IDA/A01/内容/资料/Pinpointing Insecure Cryptographic Keys from.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/内容/资料/Pinpointing Insecure Cryptographic Keys from.pdf -------------------------------------------------------------------------------- /Tool/IDA/A01/内容/资料/ReFormat Automatic Reverse Engineering of.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/内容/资料/ReFormat Automatic Reverse Engineering of.pdf -------------------------------------------------------------------------------- /Tool/IDA/A01/内容/资料/openssl编程.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/内容/资料/openssl编程.pdf -------------------------------------------------------------------------------- /Tool/IDA/A01/内容/资料/polyglot_ccs07_av.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/内容/资料/polyglot_ccs07_av.pdf -------------------------------------------------------------------------------- /Tool/IDA/A01/内容/资料/二进制程序中加解密函数的定位-焦龙龙-2018-06-17-19_00_00.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A01/内容/资料/二进制程序中加解密函数的定位-焦龙龙-2018-06-17-19_00_00.pdf -------------------------------------------------------------------------------- /Tool/IDA/A02/README.md: -------------------------------------------------------------------------------- 1 | ## 1.1 IDA静态调试硬编码破解端口检测反调试 2 | 3 | ### 1.1.1 常见Frida反调试 4 | 5 | 1. 遍历连接手机所有端口发送`D-bus`消息,如果返回"REJECT"这个特征则认为存在frida-server 6 | 2. 直接调用`openat`的`syscall`的检测在`text`节表中搜索`frida-gadget*.so / frida-agent*.so`字符串,避免了`hook` `libc`来anti-anti的方法。 [frida-detection-demo/native-lib.cpp at master · b-...](https://github.com/b-mueller/frida-detection-demo/blob/master/AntiFrida/app/src/main/cpp/native-lib.cpp) 7 | 3. 内存中存在`frida rpc`字符串,认为有frida-server [AntiFrida/detect.cpp at master · qtfreet00/AntiFri...](https://github.com/qtfreet00/AntiFrida/blob/master/app/src/main/cpp/detect.cpp) 8 | 9 | 10 | 11 | ### 1.1.2 某反调试代码实例 12 | 13 | ```c++ 14 | while (1) { 15 | 16 | /* 17 | * 1: Frida Server Detection. 18 | */ 19 | 20 | for(i = 0 ; i <= 65535 ; i++) { 21 | // 开启一个socket 22 | sock = socket(AF_INET , SOCK_STREAM , 0); 23 | // 拿到socket的port 24 | sa.sin_port = htons(i); 25 | // 连接端口 26 | if (connect(sock , (struct sockaddr*)&sa , sizeof sa) != -1) { 27 | memset(res, 0 , 7); 28 | // 发送 "\x00"、 "AUTH\r\n"给socket 29 | send(sock, "\x00", 1, NULL); 30 | send(sock, "AUTH\r\n", 6, NULL); 31 | 32 | usleep(100); // Give it some time to answer 33 | // 等待返回内容 34 | if ((ret = recv(sock, res, 6, MSG_DONTWAIT)) != -1) { 35 | // 检测原理 res跟REJECT对比,如果相同就代表检测到了frida 36 | // 可以hook strcmp函数,让他们返回永远不为0,也可也过反调试。 37 | // 需要动静态分析 38 | if (strcmp(res, "REJECT") == 0) { 39 | __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "FRIDA DETECTED [1] - frida server running on port %d!", i); 40 | } 41 | } 42 | } 43 | 44 | close(sock); 45 | } 46 | 47 | extern "C" 48 | JNIEXPORT void JNICALL Java_sg_vantagepoint_antifrida_MainActivity_init(JNIEnv *env, jobject thisObj) { 49 | pthread_t t; 50 | // 开启一个线程进入detect_frida_loop 检测frida loop 51 | // 也可以hook pthread_create。让他不创建线程。 52 | pthread_create(&t, NULL, detect_frida_loop, (void *)NULL); 53 | } 54 | ``` 55 | 56 | TracePid fgets 反调试 57 | 58 | ![](pic/01.a.png) 59 | 60 | ### 1.1.3 修改硬编码破解反调试 61 | 62 | idaNew打开so文件,找到判断的地方,因为是和'reject'做对比检测,找到reject。 63 | 64 | ![](pic/01.b.png) 65 | 66 | 选中, 进入hex view,把硬编码修改, 右键选择edit, 43和54任意修改,reject变成别的字就可以,可以使用[hex to ascii](https://www.rapidtables.com/convert/number/hex-to-ascii.html)查看,右键选择 apply changes保存。 67 | 68 | 全局修改:edit-> patch program -> apply patches to input file 保存。(同时保存备份文件,用md5对修改前、修改后两个so文件做对比,看是否修改保存成功。) 69 | 70 | ![](pic/01.c.png) 71 | 72 | objection hook住app,找到native-lib.so(代码所在的so库,不一定是native-lib.so)所在的地址,使用adb shell 进入地址,找到对应so文件。把修改后的so文件push到原native-lib.so所在的地址,替换之前的so文件。 73 | 74 | 直接保存so文件,运行app,修改后的代码是不生效的,需要找到要修改的so库的所在地址,删除原文件,修改后的so文件重新push进去。或者使用apktool重打包,[签名工具](https://github.com/patrickfav/uber-apk-signer)。 75 | 76 | **总结**:需要动静态分析。可以把它用来检测、匹配的特征 全部硬编码替换掉,只要程序正常运行。 77 | 78 | 79 | 80 | ## 1.2 参考链接 81 | 82 | 知识星球搜索反调试 83 | 84 | https://www.rapidtables.com/convert/number/hex-to-ascii.html 85 | 86 | https://github.com/patrickfav/uber-apk-signer 87 | 88 | https://mp.weixin.qq.com/s/xlgtU4xqoMqv2oXCMko7yQ 89 | 90 | -------------------------------------------------------------------------------- /Tool/IDA/A02/pic/01.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A02/pic/01.a.png -------------------------------------------------------------------------------- /Tool/IDA/A02/pic/01.b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A02/pic/01.b.png -------------------------------------------------------------------------------- /Tool/IDA/A02/pic/01.c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/IDA/A02/pic/01.c.png -------------------------------------------------------------------------------- /Tool/Unidbg/A01/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | - [基础配置](#基础配置) 6 | - [0x01. 初始化](#0x01-初始化) 7 | - [0x02. 执行目标函数--参数构造](#0x02-执行目标函数--参数构造) 8 | - [字节数组以及布尔值](#字节数组以及布尔值) 9 | - [context以及字符串类型](#context以及字符串类型) 10 | - [treemap](#treemap) 11 | - [对象数组](#对象数组) 12 | - [Long参数的传递](#Long参数的传递) 13 | 14 | 15 | 16 | ## 基础配置 17 | 18 | ### 0x01. 初始化 19 | 20 | ```java 21 | package com.lession1; 22 | 23 | // 导入通用且标准的类库 24 | import com.github.unidbg.linux.android.dvm.AbstractJni; 25 | import com.github.unidbg.AndroidEmulator; 26 | import com.github.unidbg.Module; 27 | import com.github.unidbg.linux.android.AndroidEmulatorBuilder; 28 | import com.github.unidbg.linux.android.AndroidResolver; 29 | import com.github.unidbg.linux.android.dvm.*; 30 | import com.github.unidbg.linux.android.dvm.array.ByteArray; 31 | import com.github.unidbg.memory.Memory; 32 | 33 | import java.io.File; 34 | 35 | // 继承AbstractJni类 36 | public class oasis extends AbstractJni{ 37 | private final AndroidEmulator emulator; 38 | private final VM vm; 39 | private final Module module; 40 | 41 | oasis() { 42 | // 创建模拟器实例,进程名建议依照实际进程名填写,可以规避针对进程名的校验 43 | emulator = AndroidEmulatorBuilder.for32Bit().setProcessName("com.sina.oasis").build(); 44 | // 获取模拟器的内存操作接口 45 | final Memory memory = emulator.getMemory(); 46 | // 设置系统类库解析 47 | memory.setLibraryResolver(new AndroidResolver(23)); 48 | // 创建Android虚拟机,传入APK,Unidbg可以替我们做部分签名校验的工作 49 | // 如果创建Android虚拟机时,选择不传入APK,填入null,那么样本在JNI OnLoad中所做的签名校验,就需要手动补环境校验 50 | vm = emulator.createDalvikVM(new File("unidbg-android/src/test/java/com/lession1/lvzhou.apk")); 51 | // 加载目标SO, 加载so到虚拟内存 52 | DalvikModule dm = vm.loadLibrary(new File("unidbg-android/src/test/java/com/lession1/liboasiscore.so"), true); 53 | //获取本SO模块的句柄,后续需要用它 54 | module = dm.getModule(); 55 | // 设置JNI 56 | vm.setJni(this); 57 | //打印日志 58 | vm.setVerbose(true); 59 | // 调用JNI OnLoad,可以看到JNI中做的事情,比如动态注册以及签名校验等。如果没有使用可以注释掉。 60 | dm.callJNI_OnLoad(emulator); 61 | }; 62 | 63 | public static void main(String[] args) { 64 | oasis test = new oasis(); 65 | } 66 | } 67 | ``` 68 | 69 | ### 0x02. 执行目标函数--参数构造 70 | 71 | - 字节数组需要裹上unidbg的包装类,并加到本地变量里,两件事缺一不可。 72 | - 除了基本类型(byte、char、short、int、long、float、double、 boolean),其他的对象类型一律要手动 `addLocalObject`。 73 | - vm.getObject(number.intValue()).getValue().toString() 解释:在DalvikVM中有Map存储了jni交互的对象,key是该对象的hash,value是该对象。这个intValue就是这个对象的hash,通过vm.getObject方法,来取出这个hash对应的Object。 74 | 75 | #### 字节数组以及布尔值 76 | 77 | ```java 78 | public String getS(){ 79 | // args list 80 | List list = new ArrayList<>(10); 81 | // arg1 env 82 | list.add(vm.getJNIEnv()); 83 | // arg2 jobject/jclazz 一般用不到,直接填0 84 | list.add(0); 85 | // arg3 bytes 86 | String input = "aid=01A-khBWIm48A079Pz_DMW6PyZR8" + 87 | "uyTumcCNm4e8awxyC2ANU.&cfrom=28B529501" + 88 | "0&cuid=5999578300&noncestr=46274W9279Hr1" + 89 | "X49A5X058z7ZVz024&platform=ANDROID×tamp" + 90 | "=1621437643609&ua=Xiaomi-MIX2S__oasis__3.5.8_" + 91 | "_Android__Android10&version=3.5.8&vid=10190135" + 92 | "94003&wm=20004_90024"; 93 | byte[] inputByte = input.getBytes(StandardCharsets.UTF_8); 94 | ByteArray inputByteArray = new ByteArray(vm,inputByte); 95 | list.add(vm.addLocalObject(inputByteArray)); 96 | // arg4 ,boolean false 填入0 97 | list.add(0); 98 | // 参数准备完成 99 | // call function 100 | Number number = module.callFunction(emulator, 0xC365, list.toArray())[0]; 101 | String result = vm.getObject(number.intValue()).getValue().toString(); 102 | return result; 103 | } 104 | ``` 105 | 106 | #### context以及字符串类型 107 | 108 | ```java 109 | public String calculateS(){ 110 | List list = new ArrayList<>(10); 111 | // 第一个参数是env 112 | list.add(vm.getJNIEnv()); 113 | // 第二个参数,实例方法是jobject,静态方法是jclazz,直接填0,一般用不到。 114 | list.add(0); 115 | // 通过虚拟机创建一个context实例,其类型为DvmObject 116 | DvmObject context = vm.resolveClass("android/content/Context").newObject(null); 117 | list.add(vm.addLocalObject(context)); 118 | list.add(vm.addLocalObject(new StringObject(vm, "12345"))); 119 | list.add(vm.addLocalObject(new StringObject(vm, "r0ysue"))); 120 | // 因为代码是thumb模式,别忘了+1 121 | Number number = module.callFunction(emulator, 0x1E7C + 1, list.toArray())[0]; 122 | String result = vm.getObject(number.intValue()).getValue().toString(); 123 | return result; 124 | }; 125 | ``` 126 | 127 | #### treemap 128 | 129 | ```java 130 | public void s(){ 131 | TreeMap keymap = new TreeMap(); 132 | keymap.put("appkey", "1d8b6e7d45233436"); 133 | keymap.put("autoplay_card", "11"); 134 | keymap.put("banner_hash", "10687342131252771522"); 135 | keymap.put("build", "6180500"); 136 | keymap.put("c_locale", "zh_CN"); 137 | keymap.put("channel", "shenma117"); 138 | keymap.put("column", "2"); 139 | keymap.put("device_name", "MIX2S"); 140 | keymap.put("device_type", "0"); 141 | keymap.put("flush", "6"); 142 | keymap.put("ts", "1612693177") 143 | }; 144 | ``` 145 | 146 | - 可以照着StringObject重新写一个,也可以不这么麻烦,直接返回一个“空壳”,Native中对treemap做了操作再补对应的方法,这样比较经济实惠。 147 | - 代码中补齐了treeMap的继承关系:map→AbstractMap→TreeMap,这么做是必要的,否则在有些情况下会报错。 148 | 149 | ```java 150 | public void s(){ 151 | List list = new ArrayList<>(10); 152 | list.add(vm.getJNIEnv()); // 第一个参数是env 153 | list.add(0); // 第二个参数,实例方法是jobject,静态方法是jclazz,直接填0,一般用不到。 154 | TreeMap keymap = new TreeMap(); 155 | keymap.put("ad_extra", "E1133C23F36571A3F1FDE6B325B17419AAD45287455E5292A19CF51300EAF0F2664C808E2C407FBD9E50BD48F8ED17334F4E2D3A07153630BF62F10DC5E53C42E32274C6076A5593C23EE6587F453F57B8457654CB3DCE90FAE943E2AF5FFAE78E574D02B8BBDFE640AE98B8F0247EC0970D2FD46D84B958E877628A8E90F7181CC16DD22A41AE9E1C2B9CB993F33B65E0B287312E8351ADC4A9515123966ACF8031FF4440EC4C472C78C8B0C6C8D5EA9AB9E579966AD4B9D23F65C40661A73958130E4D71F564B27C4533C14335EA64DD6E28C29CD92D5A8037DCD04C8CCEAEBECCE10EAAE0FAC91C788ECD424D8473CAA67D424450431467491B34A1450A781F341ABB8073C68DBCCC9863F829457C74DBD89C7A867C8B619EBB21F313D3021007D23D3776DA083A7E09CBA5A9875944C745BB691971BFE943BD468138BD727BF861869A68EA274719D66276BD2C3BB57867F45B11D6B1A778E7051B317967F8A5EAF132607242B12C9020328C80A1BBBF28E2E228C8C7CDACD1F6CC7500A08BA24C4B9E4BC9B69E039216AA8B0566B0C50A07F65255CE38F92124CB91D1C1C39A3C5F7D50E57DCD25C6684A57E1F56489AE39BDBC5CFE13C540CA025C42A3F0F3DA9882F2A1D0B5B1B36F020935FD64D58A47EF83213949130B956F12DB92B0546DADC1B605D9A3ED242C8D7EF02433A6C8E3C402C669447A7F151866E66383172A8A846CE49ACE61AD00C1E42223"); 156 | keymap.put("appkey", "1d8b6e7d45233436"); 157 | keymap.put("autoplay_card", "11"); 158 | keymap.put("banner_hash", "10687342131252771522"); 159 | keymap.put("build", "6180500"); 160 | keymap.put("c_locale", "zh_CN"); 161 | keymap.put("channel", "shenma117"); 162 | keymap.put("column", "2"); 163 | keymap.put("device_name", "MIX2S"); 164 | keymap.put("device_type", "0"); 165 | keymap.put("flush", "6"); 166 | keymap.put("ts", "1612693177"); 167 | 168 | DvmClass Map = vm.resolveClass("java/util/Map"); 169 | DvmClass AbstractMap = vm.resolveClass("java/util/AbstractMap",Map); 170 | DvmObject input_map = vm.resolveClass("java/util/TreeMap", AbstractMap).newObject(keymap); 171 | list.add(vm.addLocalObject(input_map)); 172 | Number number = module.callFunction(emulator, 0x1c97, list.toArray())[0]; 173 | DvmObject result = vm.getObject(number.intValue()); 174 | }; 175 | ``` 176 | 177 | #### 对象数组 178 | 179 | [原文传送](https://blog.csdn.net/qq_38851536/article/details/118000259) 180 | 181 | ```java 182 | public String main203(){ 183 | List list = new ArrayList<>(10); 184 | list.add(vm.getJNIEnv()); 185 | list.add(0); 186 | list.add(203); 187 | StringObject input2_1 = new StringObject(vm, "9b69f861-e054-4bc4-9daf-d36ae205ed3e"); 188 | ByteArray input2_2 = new ByteArray(vm, "GET /aggroup/homepage/display __r0ysue".getBytes(StandardCharsets.UTF_8)); 189 | DvmInteger input2_3 = DvmInteger.valueOf(vm, 2); 190 | vm.addLocalObject(input2_1); 191 | vm.addLocalObject(input2_2); 192 | vm.addLocalObject(input2_3); 193 | // 完整的参数2 194 | list.add(vm.addLocalObject(new ArrayObject(input2_1, input2_2, input2_3))); 195 | Number number = module.callFunction(emulator, 0x5a38d, list.toArray())[0]; 196 | return vm.getObject(number.intValue()).getValue().toString(); 197 | }; 198 | 199 | 指定一个空对象的对象数组: 200 | public void main111(){ 201 | List list = new ArrayList<>(10); 202 | list.add(vm.getJNIEnv()); 203 | list.add(0); 204 | list.add(111); 205 | DvmObject obj = vm.resolveClass("java/lang/object").newObject(null); 206 | vm.addLocalObject(obj); 207 | ArrayObject myobject = new ArrayObject(obj); 208 | vm.addLocalObject(myobject); 209 | list.add(vm.addLocalObject(myobject)); 210 | module.callFunction(emulator, 0x5a38d, list.toArray()); 211 | }; 212 | ``` 213 | 214 | #### Long参数的传递 215 | 216 | 假设一个native函数中参数是long类型: 217 | 218 | ![](pic/01.png) 219 | 220 | 在编译成arm32的SO时,一定概率会被转成两个int: 221 | 222 | > long a = 0x1000L → int a1 = 0,int a2 = 0x1000 223 | 224 | 在Unidbg主动调用时,一定要记得处理,否则会出问题。这是一个常见问题,JAVA层传入的时间戳,常常就是jlong: 225 | 226 | 处理办法有2个: 227 | 228 | - 是按照SO的情况,传给它两个int。 229 | 230 | - 是按照传入诸如 long tm= 1621265630L的标准写法,Unidbg自动帮我们分割成两个。 231 | -------------------------------------------------------------------------------- /Tool/Unidbg/A01/pic/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/Unidbg/A01/pic/01.png -------------------------------------------------------------------------------- /Tool/Unidbg/A02/pic/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/Unidbg/A02/pic/01.png -------------------------------------------------------------------------------- /Tool/Unidbg/A02/pic/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/Unidbg/A02/pic/02.png -------------------------------------------------------------------------------- /Tool/Unidbg/A02/pic/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/Unidbg/A02/pic/03.png -------------------------------------------------------------------------------- /Tool/Unidbg/A02/pic/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/Unidbg/A02/pic/04.png -------------------------------------------------------------------------------- /Tool/Unidbg/A02/pic/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/Unidbg/A02/pic/05.png -------------------------------------------------------------------------------- /Tool/Unidbg/A02/pic/06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/Unidbg/A02/pic/06.png -------------------------------------------------------------------------------- /Tool/Unidbg/A02/pic/07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/Unidbg/A02/pic/07.png -------------------------------------------------------------------------------- /Tool/Unidbg/A02/pic/08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/Unidbg/A02/pic/08.png -------------------------------------------------------------------------------- /Tool/Unidbg/A02/pic/09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/Unidbg/A02/pic/09.png -------------------------------------------------------------------------------- /Tool/Unidbg/A02/pic/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/Unidbg/A02/pic/10.png -------------------------------------------------------------------------------- /Tool/Unidbg/A02/pic/planet.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/Unidbg/A02/pic/planet.jpeg -------------------------------------------------------------------------------- /Tool/Unidbg/A03/pic/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/Unidbg/A03/pic/01.png -------------------------------------------------------------------------------- /Tool/Unidbg/A03/pic/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/Unidbg/A03/pic/02.png -------------------------------------------------------------------------------- /Tool/Unidbg/A03/pic/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/Unidbg/A03/pic/03.png -------------------------------------------------------------------------------- /Tool/Unidbg/A03/pic/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/Unidbg/A03/pic/04.png -------------------------------------------------------------------------------- /Tool/Unidbg/A03/pic/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/Unidbg/A03/pic/05.png -------------------------------------------------------------------------------- /Tool/Unidbg/A03/pic/06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/Unidbg/A03/pic/06.png -------------------------------------------------------------------------------- /Tool/Unidbg/A03/pic/07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/Unidbg/A03/pic/07.png -------------------------------------------------------------------------------- /Tool/Unidbg/A03/pic/08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/Unidbg/A03/pic/08.png -------------------------------------------------------------------------------- /Tool/Unidbg/A03/pic/09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/Unidbg/A03/pic/09.png -------------------------------------------------------------------------------- /Tool/Unidbg/A03/pic/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/Unidbg/A03/pic/10.png -------------------------------------------------------------------------------- /Tool/XPOSED/A01/README.md: -------------------------------------------------------------------------------- 1 | ### Xposed Api 2 | 3 | [Xposed 源码地址](https://api.xposed.info/reference/packages.html) 4 | 5 | [以下hook目标app源码](https://github.com/heyhu/xposeProject) 6 | 7 | 8 | - [Hook 案例toastMessage方法](https://github.com/heyhu/xposeProject/blob/main/app/src/main/java/com/example/xposed1/HookMessage.java) 9 | 10 | > $ hook指定目标函数加载 前/后以及执行顺序 11 | > 12 | > $ 参数/返回值打印 13 | > 14 | > $ 参数/返回值替换 15 | > 16 | > $ 调用栈打印 17 | > 18 | > $ 通过param.thisObject 来获取实例 19 | > 20 | > $ 获取类的两种方法: 21 | 22 | ``` 23 | 1. XposedHelpers.findClass 24 | 2. loadPackageParam.classLoader.loadClass(className) 25 | ``` 26 | 27 | - [Hook XposedBridge hookAllMethods方法](https://github.com/heyhu/xposeProject/blob/main/app/src/main/java/com/example/xposed1/practice/HookAllMethod.java) 28 | 29 | > $ 使用hookAllMethods Hook住指定方法 30 | > 31 | > $ 通过hook类的实例方法获得类的实例 32 | > 33 | > $ 主动调用动态方法 34 | 35 | - [Hook 带壳App](https://github.com/heyhu/xposeProject/blob/main/app/src/main/java/com/example/xposed1/practice/HookApplication.java) 36 | xpose 不能直接hook到带壳app下的类。 37 | 38 | > $ Hook壳原理 39 | > 40 | > $ Hook到目标类 41 | 42 | - [Hook 构造方法](https://github.com/heyhu/xposeProject/blob/main/app/src/main/java/com/example/xposed1/practice/HookApplication.java) 43 | 44 | > $ Hook构造方法并挂钩 45 | > 46 | > $ 获取实例 47 | > 48 | > $ 返回给定对象实例中对象字段的值 49 | 50 | - [复现XposedHelpers中某些方法](https://github.com/heyhu/xposeProject/blob/main/app/src/main/java/com/example/xposed1/practice/HookHelpers.java) 51 | 52 | > $ callMethod 53 | > 54 | > $ getObjectField 55 | > 56 | > $ getStaticIntField 57 | 58 | - [复现loadPackageParam的属性](https://github.com/heyhu/xposeProject/blob/main/app/src/main/java/com/example/xposed1/practice/HookLp.java) 59 | 60 | > $ 过滤系统版本 61 | > 62 | > $ 打印进程名 63 | > 64 | > $ 打印包名 65 | > 66 | > $ 获取ClassLoader,用于查找包名等。 67 | 68 | - [Hook 多dex apk](https://github.com/heyhu/xposeProject/blob/main/app/src/main/java/com/example/xposed1/practice/HookMoreDex.java) 69 | 70 | > $ hook 多dex问题 71 | > 72 | > $ findAndHookMethod可以指定参数类型指定hook特定的重载方法 73 | 74 | - [主动调用内存爆破](https://github.com/heyhu/xposeProject/blob/main/app/src/main/java/com/example/xposed1/practice/HookVerifier.java) 75 | 76 | > $ XposedHelpers.callStaticMethod 主动调用 77 | > 78 | > $ 反射主动调用 79 | > 80 | > $ context构造 81 | 82 | - [NanoHttpd 算法主动暴露](https://github.com/heyhu/xposeProject/blob/main/app/src/main/java/com/example/xposed1/practice/HookVerifier.java) 83 | 84 | > $ 使用http服务暴露算法 85 | 86 | - 获取实例的三种方式 87 | 88 | $ Hook一个实例方法来获取实例 89 | 90 | $ 获取构造方法来获取实例 91 | > 还可以findConstructorExact获得构造函数,然后.newInstance() 获取实例 92 | mNotificationLightConstructor = XposedHelpers.findConstructorExact(CLASS_NOTIFICATION_RECORD+".Light", mContext.getClassLoader(),int.class, int.class, int.class); 93 | return mNotificationLightConstructor.newInstance(color, onMs, offMs); 94 | 95 | $ xposed.newInstance(clazz) 获取实例 96 | 97 | - 为什么HookMessage类在 com.example.xposed1包下,查看包下面所有的类却没有HookMessage? 98 | 99 | > 因为 HookMessage implements IXposedHookLoadPackage, 此类实现了接口,所以搜索不到,他不属于原本的包。 100 | 101 | - 查找 HookMessage 为什么会出现两个? 102 | ![](pic/01.a.png) 103 | > HookMessage下的XC_MethodHook 就是 HookMessage$1 ,他是匿名的内部类,它有 beforeHookedMethod和 afterHookedMethod 两个方法,如果想hook XC_MethodHook 函数,那么就需要hook HookMessage$1, 104 | 假如一个类有多个hook 方法比如多个XC_MethodHook ,那么就具有多个HookMessage内部类,比如HookMessage$1、HookMessage$2等。 105 | 106 | - 如何定位className、XC_MethodHook 是属于哪个进程的内部类。 107 | > if (loadPackageParam.packageName.equals("com.example.xposed1")) { 108 | 查看进程名等于谁,就可以找到。hook 的包名为com.example.xposed1 109 | 110 | - 构造函数解释 111 | ![](pic/02.a.png) 112 | 113 | > java初始化设置属性的时候,是用构造函数来设置的。new DemoHelper("123") 给类传参数。 114 | > XposedHelpers.findConstructorExact(CLASS_SHOW_STACK_ACTION_BUTTON_EVENT, cl, boolean.class).newInstance(true)); -------------------------------------------------------------------------------- /Tool/XPOSED/A01/pic/01.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/XPOSED/A01/pic/01.a.png -------------------------------------------------------------------------------- /Tool/XPOSED/A01/pic/02.a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyhu/AndroidReverseStudy/6291069375ad0ae50c2d557ebffd30ade2afca26/Tool/XPOSED/A01/pic/02.a.png --------------------------------------------------------------------------------