java写测试小工具_移动端测试 - 如何快速的开发一款测试小工具

本文介绍了如何使用Java开发一个简单的GUI测试工具,以提高移动端测试效率。通过Intellij IDEA创建GUI界面,处理数据,调用C编译的动态库进行加密,并使用Obfuscator-LLVM混淆代码,增强安全性。文章详细阐述了从创建GUI到打包成jar,再到调用动态库和混淆的过程,展示了如何通过定制工具简化测试工作。
摘要由CSDN通过智能技术生成

最近在测试一些需求时感觉额外的费力,例如快速构建非重复性请求+统计结果。通过手动操作应用的方式触发请求,不但需要修改代码,还得配置相应的测试环境。使用抓包软件修改请求又需要重新计算签名,否则会导致校验失败。综上种种,需要开发一款定制的工具来辅助进行测试。

项目是以Android客户端的请求为基础,所以设计的思路是用java写一个简单的GUI并处理数据,这样更方便修改请求。native层负责签名,最后将项目打包成jar直接使用。

主要步骤如下(本文环境均在macOS Mojave系统):

1、Intellij IDEA通过GUI Form创建图形界面

2、Java层处理数据

3、C实现加密算法并编译成动态库

4、项目打成jar包

5、jar包调用动态库

6、Obfuscator-LLVM(ollvm)混淆

一、开发简单的GUI交互界面

页面布局极为简单,这里用Intellij IDEA通过GUI Form创建图形界面的方式实现。

1、创建新的GUI Form

项目中File -> New -> GUI Form

1e0c917d69e8?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

2、绘制布局

在右侧点击控件,然后再点击想要放置的位置,就可以添加控件了,控件的属性可以在左侧的窗口中设置,例如preferredSize等等。

1e0c917d69e8?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

3、跳转到绑定的class

选中一个控件,使用快捷键 fn + F4 跳转到Form绑定的class类。

1e0c917d69e8?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

4、初始化界面

选中panel,快捷键⌘N键Generate,点击上图中的Form main(),即可创建main() 并且初始化界面。

1e0c917d69e8?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

5、运行

Run一下Main()就可以看到我们创建的GUI了。接下来就是设置各种监听事件和逻辑处理。

1e0c917d69e8?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

二、处理数据

1、Java工程导入JSONObject

处理服务端返回的数据时需要用到json库的相关方法,因此需要导入库。

这里直接从Git下载https://github.com/stleary/JSON-java,在工程中新建package -> org.json,然后把所有文件拷贝org.json目录下,就可以使用了。

1e0c917d69e8?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

2、Java调用CURL命令

原始数据的采集是curl格式,偷点懒代码中也是直接调用curl命令。

1e0c917d69e8?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

开始的时候,直接把整个curl命令字符串传了进去,但是总是不能顺利执行。后面查了下资料,需要把curl命令切割成数组,再执行才能成功。

# 错误的演示

String curl = "curl xxxxx";

Process process = Runtime.getRuntime().exec(curl);

# 正确的演示

String[] cmd = {"curl", "-H", "Host: www.xxx.com"};

Process process = Runtime.getRuntime().exec(cmd);

3、巧用正则表达式处理数据

上面说到要把原始的curl命令拆成数组,这里就需要正则上场了。

仔细观察curl命令,发现可以按照空格来切割字符串。唯一需要注意的是单引号内的空格需要保留,以免破坏某些诸如设备信息等数据的格式。这里有个取巧的方法,既然需要按照空格拆分又不能拆分单引号里面的内容,那么可以把单引号之外的空格全部替换为某个字符,然后按照这个特定字符再切割curl命令就可以了。

匹配单引号之外的所有空格

# 伪代码

regex = " (?=([^']*['][^']*['])*[^']*$)";

command.replaceAll(regex, "awsomeReg");

String[] curl = command.split("awsomeReg");

三、Java调用动态库

1、调用动态库

在Java中调用动态库也很单,使用System.load(file name)或者System.loadLibrary(lib-name)。但是这两种方法都不够灵活,后面还会再讲到。

2、编译动态库文件

加密算法是在Android native实现的,动态库也是基于arm的,所以不能直接在mac上使用,需要手动重新编译一下。得益于mac系统的便利性,省去了很多环境配置的麻烦。

首先生成.h文件,接下来可以用gcc来进行编译,编译成功后会生成libxxx.jnilib文件,这个就是我们能够通过java直接调用的动态库了。

1e0c917d69e8?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

但是这样编译的话第一次会报缺少jni_md.h的错误。不过不用担心,这个问题很好解决,把对应的.h文件拷贝到jdk的include目录就好了。

1e0c917d69e8?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

四、Intellij Idea将Java项目打成jar包

总体上只需要四步就能完成打包了:

1、菜单:File->project stucture

2、在弹窗最左侧选中Artifacts->"+",选jar,选择from modules with dependencies,然后会有配置窗口出现,配置完成后,勾选Build on make >ok保存

3、然后菜单:Build->make project

4、最后在项目目录下去找输出的jar包(路径在你添加Artifacts的时候设置的路径)

五、jar包调用动态库

这里有很多坑,运行jar的时候会发现,无法直接加载Jar包中的动态库。

这与JVM的一个系统变量有关,可以通过打印System.getProperty("java.library.path")查看。我们在任意一个目录执行jar文件的时候,系统实际上是找不到这个libxxx.jnilib(so,dll等等)动态库文件的。为了方便,我们又不可能同时提供一个jar文件和一个动态库,这样太傻了。

回过头来看System.load(String filename)这个方法,它是从本地文件系统中以指定的文件名加载代码文件,并且文件名参数必须是完整的路径名。所以我们可以在执行jar的时候,通过流的形式写出动态库到本地,然后再加载调用。

static {

try {

InputStream in = Your.class.getClassLoader().getResourceAsStream("libxxx.jnilib");

File ffile = new File("");

String filePath = null;

filePath = ffile.getAbsolutePath() + File.separator

+ "libxxx.jnilib";

File jnilib = new File(filePath);

FileOutputStream out = new FileOutputStream(jnilib);

int i;

byte[] buf = new byte[1024];

try {

while ((i = in.read(buf)) != -1) {

out.write(buf, 0, i);

}

} finally {

in.close();

out.close();

}

System.load(jnilib.getAbsolutePath());

jnilib.deleteOnExit();

} catch (Throwable e) {

try {

} catch (Throwable ee) {

throw ee;

}

}

}

这样,我们只需要一个jar文件,就可以搞定所有事情了。运行一下jar包,在json中把version改为0.1,然后提交。可以成功的看到服务端的返回数据,说明修改的请求已经通过服务端的校验。

1e0c917d69e8?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

通过这个小测试工具,可以脱离客户端做一些实时的网络请求;也可以针对特定的接口做边界值的验证;还可以做一些安全和渗透测试等等。

对于批量甚至是组合的请求,虽然GUI不能满足,但是利用工程本身却非常容易实现。例如我需要测试一个推荐策略(100页不能有重复内容),那么至少得刷上百次带翻页接口,手动完成该任务并记录结果显然不太现实。但是利用工程就容易的多,修改请求分页数据的参数,再记录返回值并对比有无重复就可以了。

所以从这里我们看出,最关键的地方不在于数据怎么组织,而是如何进行校验,也就是所谓的sign值。Java由于其容易被反编译,现在的应用已经几乎没有再把签名算法放在java层了,都统一交给了native层去做。但是需要注意的是,native代码如果不进行混淆加密,也是非常容易被反编译的。接下来就聊聊native代码的保护。

六、Obfuscator-LLVM(ollvm)混淆

我们都知道java代码容易被反编译,为了让反编译后的代码难以读懂,通常采用混淆的方式。但即使这样,一些关键的代码也难以隐藏。例如之前分析的某app协议,通过反编译工具能够清晰的看到被还原的代码。

1e0c917d69e8?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

同样的,native代码也可以被反编译。如下图所示,虽然易读性要差一些,但关键的逻辑方法都能看到,甚至加密的key也能读到。懂一点点汇编语言就能摸清程序的执行流程,会动态调式的更加毫无阻拦。由此可见native代码的安全性也不容忽视。

1e0c917d69e8?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

Obfuscator-LLVM就是这样一个项目,它旨在提供一套开源的针对LLVM的代码混淆工具,以增加对逆向工程的难度。虽然官方的版本只更新到4.0版本 LLVM-4.0,但是一些大神在此基础上做了更新和移植。这里我们采用一个移植好的版本https://github.com/heroims/obfuscator,该作者fork原版后又加入了llvm5.0,6.0,7.0以及swift-llvm5.0的版本,并扩展了一些功能。这些已经足够满足当前项目的需要了。

七、macOS配置ollvm环境

介绍完ollvm,接下来就讲下如何在macOS配置ollvm环境。

1、下载LLVM

2、编译

解压缩zip后,进入目录新建一个build目录,然后按照下面的命令编译。

mkdir build

cd build

#如果不想跑测试用例加上-DLLVM_INCLUDE_TESTS=OFF

cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_CREATE_XCODE_TOOLCHAIN=ON ../obfuscator/

make -j7

3、使用

原版ollvm中提供了3种混淆方式,分别是:

-mllvm -fla:控制流扁平化

-mllvm -sub:指令替换

-mllvm -bcf:虚假控制流程

大神移植的时候又扩展了一个字符串混淆方式,-mllvm -sobf 字符串加密,可以丰富我们的使用场景。

直接使用编译的二进制文件

build/bin/clang test.c -o test -mllvm -sub -mllvm -fla -mllvm -bcf

也可以重新编译

/build/bin/clang -shared -fPIC you.c you2.c -o libxxx.so -mllvm -sub -mllvm -sobf -mllvm -fla -mllvm -bcf

最后我们看下效果,混淆前:程序的流程非常清晰明了。

1e0c917d69e8?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

混淆后:流程加入了大量干扰的模块,并且字符串也是加密的,极大的提高了静态分析的难度。

1e0c917d69e8?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

至此,这个小工具就算完成了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值