tweakMe 修改函数及返回值

安卓Hook加密解密:实战利用tweakMe实现数据包篡改
本文介绍了如何在非root权限下,通过tweakMe技术,绕过安卓应用的加密逻辑,实现实时修改请求和返回包。通过与EchoServer交互,展示了如何轻松替换加密数据,适用于处理复杂加密场景,类似Frida的send功能的实现。

声明:

    免责声明:本文为个人作品,只做技术研究,只可用于正常的技术交流与学习,不可用于灰黑产业,不可从事违法犯罪行,严禁利用本文所介绍的技术恶意攻击,否则,后果自负!!!

上一篇文章 非root情况下安卓Hook Java方法,修改返回值_pyth0zn的博客-优快云博客

  我们讲解了tweakMe的使用方法,以及如何hook安卓api的方法,在实际工作中,我们经常遇到一些app的返回包和请求包都加密了的情况,如果我们要修改请求包,那么就需要把加密方法还原,然后自己构造数据包,然后加密发送给服务器,同样的拿到加密后的返回包,也需要用解密方法解密。这个过程如果加解密逻辑不复杂还好,但是如果是特别复杂的,比如什么动态key啊,那就太麻烦了,那么有没有简单的办法呢?请看下张图

 OK 上面的图已经描述的很明显了。

下面我们看tweakMe代码怎么写

首先我们在 util目录下新建一个工具类  InterceptEncryptOrDecrypt

package com.android.guobao.liao.apptweak.util;

import android.util.Log;


import com.android.guobao.liao.apptweak.JavaTweakBridge;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class InterceptEncryptOrDecrypt implements Callable<String> {

    private String postBody;
    public void setHttpUrl(String httpUrl) {
        this.httpUrl = httpUrl;    }

    private String httpUrl;
    private void setPostBody(String postBody) {
        this.postBody = postBody;
    }



    private String ECHO_SERVER="http://192.168.31.100:27080"; //echo server 电脑段 运行 echerServer.py



    public static String doHttp(String postBody,String httpUrl) throws ExecutionException, InterruptedException {
        InterceptEncryptOrDecrypt d1=new InterceptEncryptOrDecrypt();
        d1.setPostBody(postBody);
        d1.setHttpUrl(httpUrl);
        FutureTask<String> task=new FutureTask<>(d1);
        new Thread(task).start();
        if (!task.isDone()) {
            System.out.println("task has not finished, please wait!");
        }
        System.out.println( "task return: " + task.get());
        return  task.get();
    }



    @Override
    public String call() throws Exception {
        String rsp="";
        JavaTweakBridge.writeToLogcat(Log.ERROR,"[*****]调用前原始参数 %s \n",postBody);
        try {
            HttpURLConnection con = null;
            BufferedReader buffer = null;
            StringBuffer resultBuffer = null;
            URL url = new URL(ECHO_SERVER+httpUrl);
            //得到连接对象
            Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(
                    "192.168.31.100", 8888)); //burp端口
            con = (HttpURLConnection) url.openConnection(proxy);
            //设置请求类型
            con.setRequestMethod("POST");
            con.setRequestProperty("Content-Type", "application/json");
            //允许写出
            con.setDoOutput(true);                    //允许读入
            con.setDoInput(true);
            con.setUseCaches(false);
            OutputStream os = con.getOutputStream();
            os.write(postBody.getBytes());
            int responseCode = con.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) { // 必须返回200
                InputStream inputStream = con.getInputStream();
                //将响应流转换成字符串
                resultBuffer = new StringBuffer();
                String line;
                buffer = new BufferedReader(new InputStreamReader(inputStream, "GBK"));
                while ((line = buffer.readLine()) != null) {
                    resultBuffer.append(line);
                }

                rsp= resultBuffer.toString();
            }
        } catch (Exception e) {
            JavaTweakBridge.writeToLogcat(Log.ERROR,"echo Server 报错");
            e.printStackTrace();
        }
        JavaTweakBridge.writeToLogcat(Log.ERROR,"[*****]调用前修改后的参数 %s \n",rsp);
        return rsp;
    }
}

我们的类继承了Callable这个回调方法,主要就是多线程接受一个postBody,然后把他发送给EchoServer,echoServer 就是利用python自带的脚本起了一个27080的webserver,功能是原样输出请求包,同时这个请求用的是burp的代理

然后我们到拦截java加密函数的地方。调用这个InterceptEncryptOrDecrypt方法就好

解密是同样的道理、区别就是先执行一次原始函数,然后再把解密的结果发送给burp,然后return原来的函数就可以了

看下效果,可以看到从app提交的手机号,经过burp修改后,最后发送给服务器的是另外一个手机号,让app继续走加密的逻辑

 

 burp中的修改记录

这样我们就实现了类似frida的 send 功能,ok 本文就到这

 

C语言函数不同返回值情况多样,下面进行详细介绍: - **常规返回值**:C语言函数可以返回各种基本数据类型,如`int`、`float`、`char`等。例如一个返回`int`类型的函数可以用于计算两个整数的和: ```c int add(int a, int b) { return a + b; } ``` - **无显式返回值**:当一个函数(非`main`函数)没有显式的`return`语句时,其返回值的情况比较复杂。在`gcc`编译器下,返回值可能是不确定的,如以下代码: ```c void fun() { printf("helloworld\n"); } int func() { printf("helloworldrgerrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr\n"); fun(); } int main() { printf("%d\n", func()); // 结果为6 } ``` 这里`func`函数没有显式的`return`语句,但输出结果为6,而`clang`编译器一直返回0 [^3]。 - **字符串数组返回问题**:在一个函数中声明一个字符串数组,最后直接`return`这个数组是不可行的。因为在函数内部声明的数组是局部变量,函数执行结束后,其内存空间会被释放,返回的指针将指向无效的内存区域。 - **`scanf`函数返回值**:`scanf`函数返回值且为`int`型,其返回的值为正确按指定格式输入变量的个数,也就是能正确接收到值的变量个数。示例代码如下: ```c void main() { int a; int b; int c; printf("请输入三个整数:"); int x = scanf("%d%d%d", &a, &b, &c); printf("%d\n%d\n", a, x); } ``` 这里用变量`x`接收`scanf`函数返回值,并输出显示出来 [^2][^5]。 - **函数返回值的传递机制**:在学习C语言时,常提到“函数返回值先拷贝到临时寄存器中,再将临时寄存器拷贝到调用函数变量中”,可以从汇编角度进一步探究其原理和好处 [^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pyth0nn

送人玫瑰,手留余香

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值