乱码三千 – 分享实用IT技术

乱码三千 – 码出一个新世界


  • 首页

  • 归档

  • 搜索

Code Spring Boot Project With Kotlin by Android Studio

发表于 2020-10-30

Step 1

Modify build.gradle

  1. In Module Dir : apply plugin: ‘kotlin’ and add kotlin dependencies
1
2
3
4
5
6
7
8
9
10
11
apply plugin: 'org.springframework.boot'
apply plugin: 'java'
apply plugin: 'kotlin'//notice


dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
compile 'org.springframework.boot:spring-boot-starter:2.3.4.RELEASE'
compile 'org.springframework.boot:spring-boot-starter-web:2.3.4.RELEASE'
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72"//notice
}
  1. Project Dir : add kotlin classpath
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
buildscript {
ext {
springBootVersion = '1.5.9.RELEASE'
}
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.72"//notice
}
}

allprojects {
repositories {
google()
jcenter()
}
}

task clean(type: Delete) {
delete rootProject.buildDir
}

Step 2

  1. Code with kotlin

    tip: if you use pure kotlin, you may code in kotlin dir replace java

Step 3

Done!

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

Create Spring Boot Project With Android Studio

发表于 2020-10-30

Step 1

Modify build.gradle

  1. Module Dir
1
2
3
4
5
6
7
8
9
apply plugin: 'org.springframework.boot'
apply plugin: 'java'


dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
compile 'org.springframework.boot:spring-boot-starter:2.3.4.RELEASE'
compile 'org.springframework.boot:spring-boot-starter-web:2.3.4.RELEASE'
}
  1. Project Dir
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

buildscript {
ext {
springBootVersion = '1.5.9.RELEASE'
}
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
}
}

allprojects {
repositories {
google()
jcenter()
}
}

task clean(type: Delete) {
delete rootProject.buildDir
}

Step 2

  1. Rename Res dir And create application.properties
  2. delete useless files

Step 3

  1. Create Boot Point Class DemoApplication.java

  2. Create Control

  3. Boot And Test

  4. Package Jar

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

python字符串str和字节数组相互转化

发表于 2020-10-29

字符串转字节数组

1
2
3
4
5
6
7
s = "Hello, world!"   # str object 

#一共有三种方式 任选其一
print('str --> bytes')
print(bytes(s, encoding="utf8"))
print(str.encode(s)) # 默认 encoding="utf-8"
print(s.encode()) # 默认 encoding="utf-8"

字节数组转字符串

1
2
3
4
5
6
7
b = b"Hello, world!"  # bytes object  

#一共有三种方式 任选其一
print('\nbytes --> str')
print(str(b, encoding="utf-8"))
print(bytes.decode(b)) # 默认 encoding="utf-8"
print(b.decode()) # 默认 encoding="utf-8"

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

python中的base64加密解密

发表于 2020-10-29

介绍

Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。可查看RFC2045~RFC2049,上面有MIME的详细规范。

Base64编码是从二进制到字符的过程,可用于在HTTP环境下传递较长的标识信息。采用Base64编码具有不可读性,需要解码后才能阅读。

Base64由于以上优点被广泛应用于计算机的各个领域,然而由于输出内容中包括两个以上“符号类”字符(+, /, =),不同的应用场景又分别研制了Base64的各种“变种”。为统一和规范化Base64的输出,Base62x被视为无符号化的改进版本。

python中的base64

将url编码成base64

1
2
3
4
5
6
7
# 想将字符串转编码成base64,要先将字符串转换成二进制数据
url = "https://www.cnblogs.com/songzhixue/"
bytes_url = url.encode("utf-8")
str_url = base64.b64encode(bytes_url) # 被编码的参数必须是二进制数据
print(str_url)

b'aHR0cHM6Ly93d3cuY25ibG9ncy5jb20vc29uZ3poaXh1ZS8='

解码base64

1
2
3
4
5
6
7
# 将base64解码成字符串
import base64
url = "aHR0cHM6Ly93d3cuY25ibG9ncy5jb20vc29uZ3poaXh1ZS8="
str_url = base64.b64decode(url).decode("utf-8")
print(str_url)

'https://www.cnblogs.com/songzhixue/'

总结

  • python中base64不论是编码还是解码,返回值都为字节数组
  • 解码解的是字符串, 编码编的是字节数组

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

Python进行DES 加密和解密 解决和java结果不一致的问题

发表于 2020-10-29

Python DES CBC 加密解密代码示范

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import binascii
from pyDes import des, CBC, PAD_PKCS5


def des_encrypt(s):
"""
DES 加密
:param s: 原始字符串
:return: 加密后字符串,16进制
"""
secret_key = '20171117'
iv = secret_key
k = des(secret_key, CBC, iv, pad=None, padmode=PAD_PKCS5)
en = k.encrypt(s, padmode=PAD_PKCS5)
return binascii.b2a_hex(en)


def des_descrypt(s):
"""
DES 解密
:param s: 加密后的字符串,16进制
:return: 解密后的字符串
"""
secret_key = '20171117'
iv = secret_key
k = des(secret_key, CBC, iv, pad=None, padmode=PAD_PKCS5)
de = k.decrypt(binascii.a2b_hex(s), padmode=PAD_PKCS5)
return de


str_en = des_encrypt('zx')
print(str_en)
str_de = des_descrypt(str_en)
print(str_de)

执行以上 Python 代码,得到以下输出:

1
2
1dbbd4e9246ebffa
zx

Java DES CBC 加密解密代码示范

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;


public class Main {

public static void main(String[] args) {
String content = "zx";
String key = "20171117";

System.out.println("加密前:" + content);
byte[] encrypted = DES_CBC_Encrypt(content.getBytes(), key.getBytes());
System.out.println("加密后:" + byteToHexString(encrypted));

byte[] decrypted = DES_CBC_Decrypt(encrypted, key.getBytes());
System.out.println("解密后:" + new String(decrypted));
}

public static byte[] DES_CBC_Encrypt(byte[] content, byte[] keyBytes) {
try {
DESKeySpec keySpec = new DESKeySpec(keyBytes);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey key = keyFactory.generateSecret(keySpec);

Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(keySpec.getKey()));
byte[] result = cipher.doFinal(content);
return result;
} catch (Exception e) {
System.out.println("exception:" + e.toString());
}
return null;
}

private static byte[] DES_CBC_Decrypt(byte[] content, byte[] keyBytes) {
try {
DESKeySpec keySpec = new DESKeySpec(keyBytes);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey key = keyFactory.generateSecret(keySpec);

Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(keyBytes));
byte[] result = cipher.doFinal(content);
return result;
} catch (Exception e) {
System.out.println("exception:" + e.toString());
}
return null;
}

private static String byteToHexString(byte[] bytes) {
StringBuffer sb = new StringBuffer(bytes.length);
String sTemp;
for (int i = 0; i < bytes.length; i++) {
sTemp = Integer.toHexString(0xFF & bytes[i]);
if (sTemp.length() < 2)
sb.append(0);
sb.append(sTemp.toUpperCase());
}
return sb.toString();
}
}

执行以上 Java 代码,输出:

1
2
3
加密前:zx
加密后:1DBBD4E9246EBFFA
解密后:zx

注意事项

python中还有一个库Crypto 也是用于加密的, 但是加密的结果和java不一致, 这是个坑, 以下是Crypto加密的代码, 用于对比:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
from Crypto.Cipher import DES
import binascii
import base64

# data->被加密的字符串 key->密钥 同样传入字符串
def des_decode(data, key):
b_data = base64.b64decode(data)
iv = key.encode()
cipher = DES.new(key.encode(), iv,DES.MODE_CBC)
decrypted = cipher.decrypt(b_data)
decrypted.rstrip(b' ')
return decrypted.decode() # 解密完成后将加密时添加的多余字符'\0'删除




# data->被加密的字符串 key->密钥 同样传入字符串
def aes_encrypt(data, key):
# DES CBC模式 需向量iv
iv = key.encode()
cipher = DES.new(key.encode(),iv, DES.MODE_CBC)
# 字符串转字节数组
b_data = data.encode()
# ------ 按照16位对其 不足的补空格 ----
block_size = DES.block_size
count = len(b_data)
# text不是16的倍数那就补足为16的倍数
add_count = block_size - (count % block_size)
s_plaintext = data + (' ' * add_count)
# ------ 按照16位对其 不足的补空格 ----

b_plaintext = s_plaintext.encode()
encrypted = cipher.encrypt(b_plaintext) # des加密

return base64.b64encode(encrypted).decode()

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

Python DES EBC 加密解密代码示范

发表于 2020-10-29

Python DES EBC 加密解密代码示范

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from pyDes import des, ECB, PAD_PKCS5


def des_encrypt(s):
"""
DES 加密
:param s: 原始字符串
:return: 加密后字符串,16进制
"""
secret_key = 'ucserver'.encode()

k = des(secret_key, ECB, pad=None, padmode=PAD_PKCS5)
en = k.encrypt(s.encode(), padmode=PAD_PKCS5)
# return binascii.b2a_hex(en)
return base64.b64encode(en).decode()


def des_descrypt(s):
"""
DES 解密
:param s: 加密后的字符串,16进制
:return: 解密后的字符串
"""
secret_key = 'ucserver'.encode()

k = des(secret_key, ECB, pad=None, padmode=PAD_PKCS5)
de = k.decrypt(base64.b64decode(s), padmode=PAD_PKCS5)
return de.decode()

注意事项

python中还有一个库Crypto 也是用于加密的, 但是加密的结果和java不一致, 这是个坑, 以下是Crypto加密的代码, 用于对比:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from Crypto.Cipher import DES
import binascii
import base64

# data->被加密的字符串 key->密钥 同样传入字符串
def des_decode(data, key):
b_data = base64.b64decode(data)
cipher = DES.new(key.encode(), DES.MODE_ECB)
decrypted = cipher.decrypt(b_data)
decrypted.rstrip(b' ')
return decrypted.decode() # 解密完成后将加密时添加的多余字符'\0'删除




# data->被加密的字符串 key->密钥 同样传入字符串
def aes_encrypt(data, key):
# DES ECB模式 无需向量iv
cipher = DES.new(key.encode(), DES.MODE_ECB)
# 字符串转字节数组
b_data = data.encode()
# ------ 按照16位对其 不足的补空格 ----
block_size = DES.block_size
count = len(b_data)
# text不是16的倍数那就补足为16的倍数
add_count = block_size - (count % block_size)
s_plaintext = data + (' ' * add_count)
# ------ 按照16位对其 不足的补空格 ----

b_plaintext = s_plaintext.encode()
encrypted = cipher.encrypt(b_plaintext) # des加密

return base64.b64encode(encrypted).decode()

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

android NDK编译涉及的cpu架构种类

发表于 2020-10-28

在使用NDK编译过程中发现针对不同的CPU架构,部分支持编译调试,部分不支持调试,故记录下来,以防忘记

在Application.mk文件中有个预定义命令参数APP_ABI,是指明编译与调试的CPU架构。

目前Android系统支持以下七种不同的CPU架构:ARMv5,ARMv7(从2010年起),x86(从2011年),MIPS(从2012年),ARMv8,MIPS64和x86_64(从2014年),每一种都对应相应的ABI。

CPU架构 ABI
ARMv5 armeabi 32位,从2010年
ARMv7 armeabi-v7a 32位,从2010年
x86 x86 32位,从2011年
MIPS mips 32位,从2012年
ARMv8 arm64-v8a 64位,从2014年
MIPS64 mips64 64位,从2014年
x86_64 x86_64 64位,从2014年

相应生成arm64-v8a,mips64,x86_64下的文件需要NDK_r10以上版本支持。在Application.mk文件里配置APP_ABI的内容。例如指明某个具体的CPU架构

1
APP_ABI := arm64-v8a

或者直接生成所有的版本

1
APP_ABI := all

注意:根据不同的NDK版本,APP_ABI := all仅能生成当前版本支持的ABI信息库文件,如果需要生成最新的必须更新相应的NDK版本。

或者明确写明支持的CPU架构

1
APP_ABI := armeabi,armeabi-v7a,x86,mips,arm64-v8a,mips64,x86_64

建议采用该方法

注意:由于目前版本支持的问题,采用Eclipse+NDK+Windows集成方式开发,对应编译生成对应CPU架构的so文件是没有问题的。但是不一定可以执行调试工作,启动NDK调试模式时将会提示无法识别对应的ABI。

注意:

(1)、目前模拟器只有x86_64的没有arm64-v8a的;

(2)、在用真机测试armv8-a时,最好先通过adb shell, cat /proc/cpuinfo ,来查看下真机是否是支持armv8-a;

(3)、arm32和arm64有些配置参数不能共存,如-msoft-float仅在arm32位下支持,在arm64位下是不支持的.

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

Termux:Android 上的一款终端神器

发表于 2020-10-28

Termux 是一款基于 Android 平台的开源 Linux 终端模拟器,使用 pkg(apt) 进行软件包的管理。最重要的是,它无需 root 权限,因此,绝大多数 Android 都可以运行。

目前来说,它能做一些简单的 Linux 任务:

  • 享受 Bash 和 Zsh
  • 使用 Vim 编辑文件
  • 通过 SSH 访问服务器
  • 使用 GCC 和 Clang 编译代码
  • 使用 Git 检查项目
  • 运行 MySQL,Redis 等服务器
  • …

使用方法

因为 Termux 是一款 Linux 终端模拟器,因此,在命令的使用方面和 Linux 是一致的。在这里,我将介绍一些针对 Termux 工具的一些使用方法。

初次使用的准备工作

业内已经有了一种共识,在涉及包管理方面,尽量都会将官方源替换成国内镜像源,Termux 也不例外。初次进入 Termux 后,我们可以使用 TUNA 的 Termux 镜像:

1
$ sed -i 's@^\(deb.*stable main\)$@#\1\ndeb https://mirrors.tuna.tsinghua.edu.cn/termux stable main@' $PREFIX/etc/apt/sources.list # 更换源文件$ pkg up # 更新源文件$ pkg udpate -y && pkge upgrade # 更新系统及软件

替换为国内镜像后,接下来,需要开启 Termux 的存储权限:

1
$ termux-setup-storage

执行命令之后,会弹出权限确认窗口,选择「始终允许」即可。

权限确认

pkg 使用命令速记

  • pkg search 搜索包
  • pkg install 安装包
  • pkg uninstall 卸载包
  • pkg update 更新源
  • pkg upgrade 升级软件包
  • pkg shoe 显示某个包的详细信息

长按屏幕

如果需要对 Termux 中的内容进行复制以及粘贴内容至 Termux,可以通过长按屏幕实现。

额外按键视图

可以看到,在正常的键盘上方,还有一盘额外的功能键,分别是:ESC 键,Tab 键,CTRL 键,ALT 键,- 符号,向下以及向上功能键。有了这一行额外视图,可以更加方便地实现 Android 键盘上没有,而电脑键盘上有的功能。

音量+组合

因为 Android 键盘没有电脑键盘上的一些功能按键,此时,我们可以通过按住音量键+,再输入键盘某个字母数字键,可以达到一些功能键的作用。

  • 音量+ Q:显示/隐藏额外按键视图
  • 音量+数字键:Fx(电脑键盘上的数字功能键)
  • 音量+L:|(管道字符)
  • 音量+H:~(波浪字符)
  • 音量+U:_(下划线字符)
  • 音量+P:上一页
  • 音量+N:下一页

一些简单的应用

HTTP Server

有些时候,我们需要将 Android 上的某些文件发送到其他设备(例如笔记本,分享)。以往的解决方案一般是用微信或者 QQ 来作为中转站,现在,可以利用 Termux 搭建一个简单的文件服务器来实现。

1
$ pkg install python -y # 需要使用 Python$ ifconfig wlan0 # 查看 Android 在局域网中的 IP 地址(我的为 192.168.2.104)$ python -m http.serverServing HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/)...

命令成功运行之后,可以看到输出信息中包含了端口地址(我这里是 8000)。此时,用另外一台处于相同局域网(例如 Wi-Fi)的设备在浏览器地址输入 192.168.2.104:8000 即可访问文件服务器了。

看起来像黑客

一提到命令行,怎能少得了那些酷炫的字符如降雨一般,这看起来就很黑客。我们可以通过安装 pkg install cmartix 来实现这种效果。

参考文章

Learn Termux

Termux 高级终端安装使用配置教程

Termux 入门教程:架设手机 Server 下载文件

本文转自:https://sspai.com/post/56031

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

apk逆向工具之脱壳神器反射大师(附脱壳环境搭建、脱壳实战)

发表于 2020-10-27

相信点击进入这篇博客的小伙伴都知道并且搞过App逆向,不过有时候会遇到各种加壳的App,不让你反编译。但是道高一尺,魔高一丈,有正向加密,就有逆向解密。此篇博客博主带大家搭建脱壳环境,并且手动脱一个加了某60的壳的App。闲话少叙,直接开始吧!

一、Android系统

  环境需要一个Android系统,并且系统的版本控制在4.0-6.0之间。建议使用虚拟机/模拟器,不然你还要获取root权限,容易搞坏真机。我这里用的是网易模拟器,Android系统的版本为6.0.1.

二、安装Xposed框架

  需要root权限,虚拟机直接允许即可,真机要用第三方工具获取,网上有很多教程。

1、下载Xposed Installer

官网地址:https://repo.xposed.info/module/de.robv.android.xposed.installer

2、安装Xposed Installer

下载完毕后,直接拖入模拟器安装即可。然后打开这个App


  由于我之前安装过,所以没提示要root权限,第一次安装的时候会提示授权的,授予即可。

三、安装反射大师

  反射大师是一个支持一键脱壳的神器,貌似什么壳都能脱,不过后面更新的壳会不会添加检测机制就说不清了。。。

1、下载反射大师

下载地址:https://www.lanzous.com/i6x1kaf

2、安装ReflectMaster并授权

  直接拖入模拟器中进行安装,然后打开。会提示让你激活Xposed。




然 后 重 启 模 拟 器 ! \color{red}然后重启模拟器!然后重启模拟器!

四、脱壳实战

1、安装待脱壳的软件

  首先在模拟器中安装好待脱壳的软件,用MT管理器可以查看软件加的是什么壳。(反射大师不区分壳类型,是壳都可以脱。)

2、用反射大师打开待脱壳App

  先把软件选中,然后打开待脱壳的App。


3、脱壳(核心步骤)






4、用jadx反编译

  jadx工具可以将dex反编译成java代码。

五、总结与体会

  以上就是脱壳环境搭建与脱某60壳实战的主要内容。壳确实脱了,但是没有修复步骤,比如修改Apk中的xml、程序入口等操作。这主要是由于不同的壳,修复步骤不同

六、附上视频教程

本文转载自https://blog.csdn.net/qq_41855420/article/details/106276824

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

逆向工具之unidbg(在pc端模拟执行so文件中的函数)

发表于 2020-10-27

 昨天在逆向某App的时候,发现有个加密工具类中的native方法是用C语言编写的,隐藏在so文件中。某大佬推荐逆向工具unidbg,能在pc端直接调用so文件中的函数,最终成功解决了问题。

一、unidbg引入

  逆向某App,反编译dex得到Java代码,但是有两个加密工具类中的方法放到so文件中。



  方法的实现用的C语言编写的,放在了so文件中。在Java中,动态加载so文件,使用native方法的形式隐藏了方法的方法体。难道伟大的逆向工程就此放弃?这显然不符合我们技术人的性格,肯定要想方设法弄出来。

二、unidbg概述

  unidbg 是一个基于 unicorn 的逆向工具,可以直接调用Android和iOS中的 so 文件。项目的GitHub地址为https://github.com/zhkl0228/unidbg
  我使用unidbg,直接调用libbaseEncryptLib.so、libencryptLib.so中的方法,这样就不用想破脑袋去逆向so文件了。

备 注 : \color{red}备注:备注:so文件是unix系统中的动态连接库,属于二进制文件,作用相当于windows系统中的.dll文件。在Android中也可调用动态库文件(*.so),一般会将加密算法、密码等重要的方法、信息使用C语言编写,然后编译成so文件,增强了软件的安全性。

三、unidbg使用姿势

1、下载unidbg项目

  下载地址:https://github.com/zhkl0228/unidbg

2、导入到IDEA中

  unidbg项目用Java编写,并且上面下载的是一个标准的maven项目。我这里演示导入到IDEA中,如果你熟悉其它的IDE,也可以自己去弄。(顺带一提,如果你之前没接触过Java语言,要确保电脑安装好JDK、maven)

①、解压压缩包

②、打开IDEA,导入解压的项目


  浏览到刚刚解压好的文件夹


  后面一路无脑next即可。。。




  第一次导入此项目会自动下载一些jar包,和网速、maven服务器有关,耐心等待吧。

3、测试unidbg

  项目中的src/test/java/com/xxxx/frameworks/core/encrypt路径中有一个TTEncrypt测试用例,直接执行其中的main方法。

  控制台打印相关调用信息,说明项目导入成功。

4、运行自己的so文件

  在前面,我们不是遇到了libbaseEncryptLib.so、libencryptLib.so文件么,利用unidbg直接调用so文件中 的方法。下面演示调用libencryptLib.so文件中的getGameKey函数。

①、编写EncryptUtilsJni类

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

import com.github.unidbg.Module;
import com.github.unidbg.arm.ARMEmulator;
import com.github.unidbg.linux.android.AndroidARMEmulator;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.*;
import com.github.unidbg.memory.Memory;


import java.io.File;
import java.io.IOException;

/**
* description: EncryptUtils调用so
*
* @author hestyle
* @version 1.0
* @className unidbg->EncryptUtilsJni
* @date 2020-05-20 22:01
**/
public class EncryptUtilsJni extends AbstractJni {
// ARM模拟器
private final ARMEmulator emulator;
// vm
private final VM vm;
// 载入的模块
private final Module module;

private final DvmClass TTEncryptUtils;

/**
*
* @param soFilePath 需要执行的so文件路径
* @param classPath 需要执行的函数所在的Java类路径
* @throws IOException
*/
public EncryptUtilsJni(String soFilePath, String classPath) throws IOException {
// 创建app进程,包名可任意写
emulator = new AndroidARMEmulator("cn.hestyle");
Memory memory = emulator.getMemory();
// 作者支持19和23两个sdk
memory.setLibraryResolver(new AndroidResolver(23));
// 创建DalvikVM,利用apk本身,可以为null
vm = ((AndroidARMEmulator) emulator).createDalvikVM(null);
// (关键处1)加载so,填写so的文件路径
DalvikModule dm = vm.loadLibrary(new File(soFilePath), false);
// 调用jni
dm.callJNI_OnLoad(emulator);
module = dm.getModule();
// (关键处2)加载so文件中的哪个类,填写完整的类路径
TTEncryptUtils = vm.resolveClass(classPath);
}

/**
* 调用so文件中的指定函数
* @param methodSign 传入你要执行的函数信息,需要完整的smali语法格式的函数签名
* @param args 是即将调用的函数需要的参数
* @return 函数调用结果
*/
private String myJni(String methodSign, Object ...args) {
// 使用jni调用传入的函数签名对应的方法()
Number ret = TTEncryptUtils.callStaticJniMethod(emulator, methodSign, args);
// ret存放返回调用结果存放的地址,获得函数执行后返回值
StringObject str = vm.getObject(ret.intValue() & 0xffffffffL);
return str.getValue();
}

/**
* 关闭模拟器
* @throws IOException
*/
private void destroy() throws IOException {
emulator.close();
System.out.println("emulator destroy...");
}

public static void main(String[] args) throws IOException {
// 1、需要调用的so文件所在路径
String soFilePath = "src/test/resources/myso/libencryptLib.so";
// 2、需要调用函数所在的Java类完整路径,比如a/b/c/d等等,注意需要用/代替.
String classPath = "com/.../EncryptUtils";
// 3、需要调用函数的函数签名,我这里调用EncryptUtils中的getGameKey方法,由于此方法没有参数列表,所以不需要传入
String methodSign = "getGameKey()Ljava/lang/String;";
EncryptUtilsJni encryptUtilsJni = new EncryptUtilsJni(soFilePath, classPath);
// 输出getGameKey方法调用结果
System.err.println(encryptUtilsJni.myJni(methodSign));
encryptUtilsJni.destroy();
}
}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990

②、参数说明

  EncryptUtilsJni类中最重要的设置为main方法中的soFilePath、classPath、methodSign三个参数,它们的作用在main方法中已经注释过了,这里再次解释一下。

soFilePath,填写你需要调用的so文件路径
classPath,填写你需要调用的函数所在Java类的完整类路径。

methodSign,填写你要调用的函数签名,语法为smali。(在jadx中,直接可以看smali代码)


备 注 : \color{red}备注:备注:如果你要调用的函数还需要传入参数,直接传入myJni方法中即可,myJni方法中省略args参数就是供你传入参数。

③、执行结果

四、分析so文件的IDA工具

  IDA工具是反汇编so文件的强大工具,由于libencryptLib.so文件比较简单,并且getGameKey函数返回的是一个常量,并没有复杂的处理过程,所以可以直接查看。

  首先用IDA打开libencryptLib.so文件



  查看反汇编得到的代码。


五、总结

  unidbg确实很强大,直接在pc端模拟调用so文件,省去了反汇编逆向so文件的麻烦。上面的教程只演示了unidbg项目的导入、封装自己的调用so文件的API,其实这只是入门了,unidbg还支持断点调试so文件,也能导入到IDA中进行动态调试

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

1…343536…51

乱码三千

android程序员一枚,擅长java,kotlin,python,金融投资,欢迎交流~

505 日志
145 标签
RSS
© 2026 乱码三千
本站总访问量次
由 Hexo 强力驱动
|
主题 — NexT.Muse v5.1.4
0%