Andriod APP reverse - network request

Common modules for Android network requests

  • Common Web HTTP requests are divided into GET and POST requests. Python uses urllib and requests modules, and Android uses okhttp and retrofit modules. The relationship between okhttp and retrofit is the same as that between urllib and requests. Both of them are re-encapsulated on the basis of the former to make it more convenient to use.

  • The data packet of the Web HTTP request can be divided into two forms, the form form and the json string . In python, these two forms are distinguished by the parameters of the requests method, but in Android, okhttp will also have corresponding submissions. method of form.

  • When a web packet is received, if the received json string is received, the data needs to be deserialized. The requests module in python helps us complete this work, but in Android, the Gson module needs to be introduced to achieve deserialization change.

  • In browser web applications, cookies files are used to save user information, and xml files are used to achieve similar functions in Android, so it is also necessary to learn how to operate xml files in Android.

OKHTTP

Before using okhttp, do the following configuration:

implementation “com.squareup.okhttp3:okhttp:4.9.1”
  • Configuration, in AndroidManifest.xml, the application tag added above the same level
    can only send https requests.

  • Configuration, in AndroidManifest.xml, add android:networkSecurityConfig="@xml/network_security_config" inside the application tag

Create a new xml folder in the res directory, create a new network_security_config.xml file in it, and write the following content:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <!--禁用掉明文流量请求的检查-->
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

Create a GET request ---> [create thread] --> otherwise report an error

String username = String.valueOf(txtUser.getText());
String password = String.valueOf(txtPwd.getText());

HashMap<String, String> dataMap = new HashMap<String, String>();
dataMap.put("username", username);
dataMap.put("password", password);


// 1. 将用户名和密码 发送到后台 (第三方 OKHttp)
//  1.1 引入依赖 bulid.gradle 文件中 引入 implementation "com.squareup.okhttp3:okhttp:4.9.1"
//  1.2 在Android中,默认不允许发送网络请求; 在AndroidManifest.xml 中 配置 <uses-permission android:name="android.permission.INTERNET"/>
//  1.3 调用 OKHttp包去发送请求。

// 1.3.1 创建 GET 请求 ---> [创建线程]--> 否则报错
// 创建线程并执行 run 方法
new Thread(){
    @Override
    public void run(){
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().url("https://api.luffycity.com/api/v1/course/actual/?category_id=1").build();
        Call call = client.newCall(request);

        try {
            Response response = call.execute();      //  发送请求
            ResponseBody body = response.body();
            String resString = body.string();

            Log.i("登录界面--->", resString);
            // 获取数据并处理


        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}.start();

Create POST request ---> [create thread]

formForm format

  • Packets are submitted in a form format such as:

username=xxxx&password=123
new Thread(){
    @Override
    public void run(){
        OkHttpClient client = new OkHttpClient();
        // 构建请求体
        FormBody form = new FormBody.Builder().add("username", "xxxx").add("password", "123").build();
        // form ---> post 请求体
        Request request = new Request.Builder().url("https://api.luffycity.com/api/v1/auth/password/login/?loginWay=password").post(form).build();
        Call call = client.newCall(request);

        try {
            Response response = call.execute();      //  发送请求
            ResponseBody body = response.body();
            String resString = body.string();

            Log.i("登录界面--->", resString);
            // 获取数据并处理


        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}.start();

json format

  • The data package is submitted in json format, for example:

{
    username:"xxxx",
    password:123,
}
new Thread() {
    @Override
    public void run() {
        OkHttpClient client = new OkHttpClient();
        // 构建请求体
        // FormBody form = new FormBody.Builder().add("username", "xxxx").add("password", "123").build();

        //JSONObject json = new JSONObject();
        //json.put("username", "dk");
        //json.put("password", "123");
        JSONObject json = new JSONObject(dataMap);
        String jsonString = json.toString();
        RequestBody form = RequestBody.create(MediaType.parse("application/json;charset=utf-8"), toString());

        // form ---> post 请求体
        Request request = new Request.Builder().url("https://api.luffycity.com/api/v1/auth/password/login/?loginWay=password").post(form).build();
        Call call = client.newCall(request);

        try {
            Response response = call.execute();      //  发送请求
            ResponseBody body = response.body();
            String resString = body.string();

            // Json反序列化,字符串转换成对象.
            // json.load(json字符串) --> python
            // Android 需要 GSON  --> 引入 (implementation "com.google.code.gson:gson:2.8.6")
            //
            String responseString = "{\"token\": \"dsajkdhjksald\", \"url\": \"https://www.httpbin.org/post/\",\"dataList\":[{\"id\": 1, \"name\": \"dk\"},{\"id\": 2, \"name\": \"dkk\"}]}";
            HttpResponse res = new Gson().fromJson(responseString, HttpResponse.class);
            Log.e("登录界面--->", res.toString());  //HttpResponse{url='https://www.httpbin.org/post/', origin='101.248.149.62', dataList=[Item{id=1, name='dk'}, Item{id=2, name='dkk'}]}

            // 保存起来:cookies, localstorage
            // andorid -> xml 文件 -> data/data/com.example.myapplication/shared_prefs
            SharedPreferences sharedPreferences = getSharedPreferences("sp_MyApplication", MODE_PRIVATE);
            SharedPreferences.Editor editor= sharedPreferences.edit();
            editor.putString("token", res.token);
            editor.commit();

            // 跳转首页
            Intent in = new Intent(mcontext, IndexActivity.class);
            startActivity(in);


        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}.start();

The difference between the two is:

  • The form format uses FormBody to construct the request body

  • The json string format uses both JSONObject and RequestBody to construct the request body

request interceptor

Some request header information is carried by every HTTP request. These common request header information are implemented by middleware in python’s scrapy crawler framework, and by request interceptors in Android App’s okhttp. The following is Interceptor simple test code.

// 4. 发送请求拦截器
Interceptor interceptor = new Interceptor() {
    @NonNull
    @Override
    public Response intercept(@NonNull Chain chain) throws IOException {
        String sign = "sfsadsadsa";
        // 请求还未发送,在请求体中增加了一个请求头
        Request request = chain.request().newBuilder().addHeader("x-gorgon", sign).build();
        Response response = chain.proceed(request);
        return response;
    }
};
new Thread() {
    @Override
    public void run() {
        // 加入拦截器
        OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
        // 构建请求体
        // FormBody form = new FormBody.Builder().add("username", "xxxx").add("password", "123").build();

        //JSONObject json = new JSONObject();
        //json.put("username", "dk");
        //json.put("password", "123");
        JSONObject json = new JSONObject(dataMap);
        String jsonString = json.toString();
        RequestBody form = RequestBody.create(MediaType.parse("application/json;charset=utf-8"), toString());

        // form ---> post 请求体
        Request request = new Request.Builder().url("https://api.luffycity.com/api/v1/auth/password/login/?loginWay=password").post(form).build();
        Call call = client.newCall(request);

        try {
            Response response = call.execute();      //  发送请求
            ResponseBody body = response.body();
            String resString = body.string();

            // Json反序列化,字符串转换成对象.
            // json.load(json字符串) --> python
            // Android 需要 GSON  --> 引入 (implementation "com.google.code.gson:gson:2.8.6")
            //
            String responseString = "{\"token\": \"dsajkdhjksald\", \"url\": \"https://www.httpbin.org/post/\",\"dataList\":[{\"id\": 1, \"name\": \"dk\"},{\"id\": 2, \"name\": \"dkk\"}]}";
            HttpResponse res = new Gson().fromJson(responseString, HttpResponse.class);
            Log.e("登录界面--->", res.toString());  //HttpResponse{url='https://www.httpbin.org/post/', origin='101.248.149.62', dataList=[Item{id=1, name='dk'}, Item{id=2, name='dkk'}]}

            // 保存起来:cookies, localstorage
            // andorid -> xml 文件 -> data/data/com.example.myapplication/shared_prefs
            SharedPreferences sharedPreferences = getSharedPreferences("sp_MyApplication", MODE_PRIVATE);
            SharedPreferences.Editor editor= sharedPreferences.edit();
            editor.putString("token", res.token);
            editor.commit();

            // 跳转首页
            Intent in = new Intent(mcontext, IndexActivity.class);
            startActivity(in);


        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}.start();

The difference from the previous interceptor :

  • Created an interceptor before creating okhttp

  • When creating okhttp, add an interceptor

NO_PROXY

In order to prevent packet capture, some apps will use the NO_PROXY parameter of okhttp to prohibit the Android phone from setting a system proxy. In this case, you can use the Drony App to capture packets without a proxy, or you can use apps such as Little Yellow Bird to capture packets with a local VPN .

For agentless packet capture, please refer to: Python crawler analysis of packet capture in app agentless mode, and anti-crawling optimization scheme for this - Eeyhan - Blog Garden (cnblogs.com)


retrofit

Before using retrofit, do the following configuration:

  • Introduction, implementation "com.squareup.retrofit2:retrofit:2.9.0" in build.gradle

The specific usage method is as follows:

  1. Write interface, declare network request

package com.example.liyang;

package com.example.liyang;

import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST;
import retrofit2.http.GET;
import retrofit2.http.Query;

public interface HttpReq {
    // 向/api/v1/post 发送POST请求,表单格式 name=xx&pwd=xxx
    @POST("/api/v1/post")
    @FormUrlEncoded
    Call<ResponseBody> postLogin(@Field("name") String userName, @Field("pwd") String password);

    // 向/api/v2/xxx 发送GET请求,表单格式 ?age=xxx
    @GET("/api/v2/xxx")
    Call<ResponseBody> getInfo(@Query("age") String age);

    // 向/post/users 发送POST请求 json字符串格式 {name:xxxx,age:123}
    @POST("/post/users")
    Call<ResponseBody> postLoginJson(@Body RequestBody body);
}
  1. Call the interface, pass parameters to the interface, and send a request

new Thread() {
    @Override
    public void run() {
        Retrofit retrofit = new Retrofit.Builder().baseUrl("http://192.168.31.201:9999/").build();
        HttpReq httpRequest = retrofit.create(HttpReq.class);        
        
        // http://192.168.31.201:9999/api/v1/post  
        // name=xx&pwd=xxx
        Call<ResponseBody> call = httpRequest.postLogin("wupeiqi", "666");
        try {
            ResponseBody responseBody = call.execute().body();
            String responseString = responseBody.string();
            Log.i("登录", responseString);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}.start();
new Thread() {
    @Override
    public void run() {
        // http://192.168.31.201:9999/api/v2/xxx?age=123
        Retrofit retrofit = new Retrofit.Builder().baseUrl("http://192.168.31.201:9999/").build();
        HttpReq req = retrofit.create(HttpReq.class);
        Call<ResponseBody> call = req.getInfo("123");
        try {
            ResponseBody responseBody = call.execute().body();
            String responseString = responseBody.string();
            Log.e("Retrofit返回的结果", responseString);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}.start();
new Thread() {
    @Override
    public void run() {
        Retrofit retrofit = new Retrofit.Builder().baseUrl("http://192.168.31.201:9999/").build();
        HttpReq httpRequest = retrofit.create(HttpReq.class);

        JSONObject json = new JSONObject(dataMap);
        String jsonString = json.toString();
        RequestBody form = RequestBody.create(MediaType.parse("application/json;charset=utf-8"),jsonString);
        
        // http://192.168.31.201:9999/post/users  
        // {username:"root",password:"123456","sign":"xxxxdfsdfsdfsdfdfd"}
        Call<ResponseBody> call = httpRequest.postLoginJson(form);
        try {
            ResponseBody responseBody = call.execute().body();
            String responseString = responseBody.string();
            Log.i("登录", responseString);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}.start();

Precautions:

  • Retrofit is a further encapsulation on okhttp. It is characterized by dividing the requested url into several segments and specifying them in different places. The url can be configured more flexibly.

  • When encountering an interface written in retrofit, it is no longer to find the class that implements it, but to find the class that calls it, splicing out the requested url and finding the passed parameters

  • The code is relatively lengthy, focusing on the way of defining the interface, which determines the style of the request, the method of calling the interface, and the parameters passed. The two parts together determine the url of the request


GSON

Similar to the json module in python, it is used to serialize objects and deserialize json strings. It needs to be introduced before using Gson

implementation ‘com.google.code.gson:gson:2.8.6’
  • Serialization, object -> string type

class HttpContext{
    public int code;
    public String message;
    
    public HttpContext(int code,String msg){
        this.code = code;
        this.message = msg;
    }
}
HttpContext obj = new HttpContext(1000,"成功");
String dataString = new Gson().toJson(obj); // '{"code":1000,"Message":"成功"}'
  • Deserialization, string -> object

// JSON格式
String dataString = "{\"status\": true, \"token\": \"fffk91234ksd\", \"name\": \"武沛齐\"}";
class HttpResponse{
    public boolean status;
    public String token;
    public String name;
}
HttpResponse obj = new Gson().fromJson(dataString,HttpResponse.class);
// obj.status  obj.name  obj.token
  • If there is dictionary nesting when deserializing

String responseString = "{\"origin\": \"110.248.149.62\",\"url\": \"https://www.httpbin.org/post\",\"dataList\":[{\"id\":1,\"name\":\"一个小黑\"},{\"id\":2,\"name\":\"eric\"}]}";
class Item {
    public int id;
    public String name;
}
public class HttpResponse {
    public String url;
    public String origin;
    public ArrayList<Item> dataList;
}
HttpResponse obj = new Gson().fromJson(dataString, HttpResponse.class);
// obj.url  obj.origin
Item objItem = obj.dataList.get(1);
// objItem.name

Save to XML file

Save to location on phone:

/data/data/com.example.liyang/shared_prefs/sp_city.xml

save token

SharedPreferences sp = getSharedPreferences("sp_city", MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString("token","111111");
editor.commit();

delete token

SharedPreferences sp = getSharedPreferences("sp_city", MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.remove("token");
editor.commit();

read token

SharedPreferences sp = getSharedPreferences("sp_city", MODE_PRIVATE);
String token = sp.getString("token","");
  • Remember that the SharedPreferences object is used to read and write the local XML file of the mobile app

  • XML files are very similar to Cookies, either generated by a local algorithm or returned by an HTTP request server.


Summarize

jadx, jeb to decompile Android code:

  • keyword search

  • Check step by step according to the requested process

  • java call

Note: The small app can completely reverse it by understanding the above content.

Guess you like

Origin blog.csdn.net/m0_57126939/article/details/128849769