Primer paso de la investigacion. Se aportan el .apk, las carpetas con el apk extraido y el apk descompilado. El archivo API_DOCUMENTATION.md es un archivo donde se anotaran los descubrimientos del funcionamiento de la API, y los .py son scripts para probar la funcionalidad de la API con los métodos que vayamos encontrando. Finalmente, los archivos .js son scripts de Frida para extraer informacion de la APP durante la ejecucion.
This commit is contained in:
132
frida_scripts/frida_capture_request_body.js
Normal file
132
frida_scripts/frida_capture_request_body.js
Normal file
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* Capture REQUEST BODY using writeTo() method
|
||||
*/
|
||||
|
||||
console.log("\n[*] Capturing REQUEST Bodies\n");
|
||||
|
||||
Java.perform(function() {
|
||||
|
||||
try {
|
||||
var AuthHeaderInterceptor = Java.use("com.adif.elcanomovil.serviceNetworking.interceptors.AuthHeaderInterceptor");
|
||||
console.log("[+] Found AuthHeaderInterceptor");
|
||||
|
||||
// Try to find Buffer class
|
||||
var Buffer = null;
|
||||
var bufferNames = ["r.f", "r3.f", "okio.Buffer", "r3.Buffer"];
|
||||
for (var i = 0; i < bufferNames.length; i++) {
|
||||
try {
|
||||
Buffer = Java.use(bufferNames[i]);
|
||||
console.log("[+] Found Buffer class: " + bufferNames[i]);
|
||||
break;
|
||||
} catch (e) {
|
||||
// Try next
|
||||
}
|
||||
}
|
||||
|
||||
if (!Buffer) {
|
||||
console.log("[-] Could not find Buffer class, trying without pre-loading");
|
||||
}
|
||||
|
||||
AuthHeaderInterceptor.intercept.implementation = function(chain) {
|
||||
console.log("\n" + "=".repeat(80));
|
||||
console.log("[HTTP REQUEST]");
|
||||
|
||||
try {
|
||||
// Cast chain
|
||||
var ChainClass = Java.use("j3.g");
|
||||
var chainObj = Java.cast(chain, ChainClass);
|
||||
|
||||
// Get request
|
||||
var requestField = chainObj.getClass().getDeclaredField("e");
|
||||
requestField.setAccessible(true);
|
||||
var request = requestField.get(chainObj);
|
||||
|
||||
if (request) {
|
||||
// Get URL
|
||||
var urlField = request.getClass().getDeclaredField("a");
|
||||
urlField.setAccessible(true);
|
||||
var urlObj = urlField.get(request);
|
||||
console.log("[URL] " + urlObj.toString());
|
||||
|
||||
// Get method
|
||||
var methodField = request.getClass().getDeclaredField("b");
|
||||
methodField.setAccessible(true);
|
||||
var method = methodField.get(request);
|
||||
console.log("[METHOD] " + method);
|
||||
|
||||
// Get request body
|
||||
var bodyField = request.getClass().getDeclaredField("d");
|
||||
bodyField.setAccessible(true);
|
||||
var reqBody = bodyField.get(request);
|
||||
|
||||
if (reqBody) {
|
||||
try {
|
||||
// If Buffer wasn't found, try to load it now
|
||||
if (!Buffer) {
|
||||
var bufferNames = ["r.f", "r3.f", "okio.Buffer", "r3.Buffer"];
|
||||
for (var i = 0; i < bufferNames.length; i++) {
|
||||
try {
|
||||
Buffer = Java.use(bufferNames[i]);
|
||||
break;
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
|
||||
if (Buffer) {
|
||||
// Create a temporary buffer
|
||||
var buffer = Buffer.$new();
|
||||
|
||||
// Try to cast buffer to BufferedSink if needed
|
||||
try {
|
||||
var BufferedSink = Java.use("r3.i");
|
||||
var sink = Java.cast(buffer, BufferedSink);
|
||||
|
||||
// Call writeTo passing the sink
|
||||
reqBody.writeTo(sink);
|
||||
} catch (e) {
|
||||
// If cast fails, try direct call
|
||||
reqBody.writeTo(buffer);
|
||||
}
|
||||
|
||||
// Read the content as UTF-8 string
|
||||
var bodyContent = buffer.B0(); // readUtf8()
|
||||
|
||||
console.log("\n[REQUEST BODY]");
|
||||
if (bodyContent && bodyContent.length > 0) {
|
||||
if (bodyContent.length > 2000) {
|
||||
console.log(bodyContent.substring(0, 2000));
|
||||
console.log("\n... (truncated, total: " + bodyContent.length + " chars)");
|
||||
} else {
|
||||
console.log(bodyContent);
|
||||
}
|
||||
} else {
|
||||
console.log("(empty)");
|
||||
}
|
||||
} else {
|
||||
console.log("\n[REQUEST BODY] Could not load Buffer class");
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.log("[REQUEST BODY ERROR] " + e);
|
||||
}
|
||||
} else {
|
||||
console.log("[REQUEST BODY] null");
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.log("[ERROR] " + e);
|
||||
}
|
||||
|
||||
console.log("=".repeat(80) + "\n");
|
||||
|
||||
// Call original
|
||||
return this.intercept(chain);
|
||||
};
|
||||
|
||||
console.log("[*] Hook installed!\n");
|
||||
|
||||
} catch (e) {
|
||||
console.log("[-] Failed: " + e);
|
||||
}
|
||||
});
|
||||
133
frida_scripts/frida_final_working.js
Normal file
133
frida_scripts/frida_final_working.js
Normal file
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* HTTP Traffic Capture - FINAL WORKING VERSION
|
||||
* Using correct method names from ResponseBody
|
||||
*/
|
||||
|
||||
console.log("\n[*] HTTP Traffic Capture - Final Working\n");
|
||||
|
||||
Java.perform(function() {
|
||||
|
||||
try {
|
||||
var AuthHeaderInterceptor = Java.use("com.adif.elcanomovil.serviceNetworking.interceptors.AuthHeaderInterceptor");
|
||||
console.log("[+] Found AuthHeaderInterceptor");
|
||||
|
||||
AuthHeaderInterceptor.intercept.implementation = function(chain) {
|
||||
console.log("\n" + "=".repeat(80));
|
||||
console.log("[HTTP REQUEST]");
|
||||
|
||||
try {
|
||||
// Cast chain to j3.g
|
||||
var ChainClass = Java.use("j3.g");
|
||||
var chainObj = Java.cast(chain, ChainClass);
|
||||
|
||||
// Get request from field "e"
|
||||
var requestField = chainObj.getClass().getDeclaredField("e");
|
||||
requestField.setAccessible(true);
|
||||
var request = requestField.get(chainObj);
|
||||
|
||||
if (request) {
|
||||
// Get URL
|
||||
var urlField = request.getClass().getDeclaredField("a");
|
||||
urlField.setAccessible(true);
|
||||
var urlObj = urlField.get(request);
|
||||
console.log("[URL] " + urlObj.toString());
|
||||
|
||||
// Get method
|
||||
var methodField = request.getClass().getDeclaredField("b");
|
||||
methodField.setAccessible(true);
|
||||
var method = methodField.get(request);
|
||||
console.log("[METHOD] " + method);
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.log("[ERROR] " + e);
|
||||
}
|
||||
|
||||
// Call original interceptor
|
||||
var response = this.intercept(chain);
|
||||
|
||||
console.log("\n[HTTP RESPONSE]");
|
||||
|
||||
try {
|
||||
if (response) {
|
||||
// Get status code
|
||||
var codeField = response.getClass().getDeclaredField("d");
|
||||
codeField.setAccessible(true);
|
||||
var code = codeField.get(response);
|
||||
console.log("[CODE] " + code);
|
||||
|
||||
// Get message
|
||||
var msgField = response.getClass().getDeclaredField("c");
|
||||
msgField.setAccessible(true);
|
||||
var message = msgField.get(response);
|
||||
console.log("[MESSAGE] " + message);
|
||||
|
||||
// Get response body
|
||||
var responseBodyField = response.getClass().getDeclaredField("g");
|
||||
responseBodyField.setAccessible(true);
|
||||
var responseBody = responseBodyField.get(response);
|
||||
|
||||
if (responseBody != null) {
|
||||
try {
|
||||
// Get source using source() method
|
||||
var source = responseBody.source(); // CORRECT METHOD NAME
|
||||
|
||||
if (source) {
|
||||
// List methods on source to see what's available
|
||||
try {
|
||||
var sourceMethods = source.getClass().getDeclaredMethods();
|
||||
var methodNames = [];
|
||||
for (var i = 0; i < sourceMethods.length; i++) {
|
||||
methodNames.push(sourceMethods[i].getName());
|
||||
}
|
||||
console.log("[SOURCE METHODS] " + methodNames.join(", "));
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
// Try different method patterns
|
||||
// Pattern 1: request all
|
||||
var Long = Java.use("java.lang.Long");
|
||||
source.request(Long.MAX_VALUE.value);
|
||||
|
||||
// Get buffer
|
||||
var buffer = source.buffer();
|
||||
|
||||
// Clone buffer
|
||||
var clone = buffer.clone();
|
||||
|
||||
// Read UTF8
|
||||
var bodyStr = clone.readUtf8();
|
||||
|
||||
if (bodyStr && bodyStr.length > 0) {
|
||||
console.log("\n[RESPONSE BODY]");
|
||||
if (bodyStr.length > 2000) {
|
||||
console.log(bodyStr.substring(0, 2000));
|
||||
console.log("\n... (truncated, total: " + bodyStr.length + " chars)");
|
||||
} else {
|
||||
console.log(bodyStr);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("[BODY READ ERROR] " + e);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("[SOURCE ERROR] " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.log("[RESPONSE ERROR] " + e);
|
||||
}
|
||||
|
||||
console.log("=".repeat(80) + "\n");
|
||||
return response;
|
||||
};
|
||||
|
||||
console.log("[*] Hook installed!\n");
|
||||
|
||||
} catch (e) {
|
||||
console.log("[-] Failed: " + e);
|
||||
}
|
||||
});
|
||||
70
frida_scripts/frida_inspect_requestbody.js
Normal file
70
frida_scripts/frida_inspect_requestbody.js
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Inspect RequestBody to see what methods we can use
|
||||
*/
|
||||
|
||||
console.log("\n[*] Inspecting RequestBody\n");
|
||||
|
||||
Java.perform(function() {
|
||||
|
||||
try {
|
||||
var AuthHeaderInterceptor = Java.use("com.adif.elcanomovil.serviceNetworking.interceptors.AuthHeaderInterceptor");
|
||||
console.log("[+] Found AuthHeaderInterceptor");
|
||||
|
||||
AuthHeaderInterceptor.intercept.implementation = function(chain) {
|
||||
|
||||
try {
|
||||
// Cast chain
|
||||
var ChainClass = Java.use("j3.g");
|
||||
var chainObj = Java.cast(chain, ChainClass);
|
||||
|
||||
// Get request
|
||||
var requestField = chainObj.getClass().getDeclaredField("e");
|
||||
requestField.setAccessible(true);
|
||||
var request = requestField.get(chainObj);
|
||||
|
||||
if (request) {
|
||||
// Get request body from field "d"
|
||||
var bodyField = request.getClass().getDeclaredField("d");
|
||||
bodyField.setAccessible(true);
|
||||
var reqBody = bodyField.get(request);
|
||||
|
||||
if (reqBody) {
|
||||
console.log("\n" + "=".repeat(80));
|
||||
console.log("[REQUEST BODY CLASS] " + reqBody.$className);
|
||||
|
||||
// List ALL methods
|
||||
console.log("\n[ALL METHODS]:");
|
||||
var methods = reqBody.getClass().getMethods();
|
||||
for (var i = 0; i < methods.length; i++) {
|
||||
var method = methods[i];
|
||||
var paramTypes = method.getParameterTypes();
|
||||
var paramStr = "";
|
||||
for (var j = 0; j < paramTypes.length; j++) {
|
||||
if (j > 0) paramStr += ", ";
|
||||
paramStr += paramTypes[j].getName();
|
||||
}
|
||||
console.log(" " + method.getName() + "(" + paramStr + ") -> " + method.getReturnType().getName());
|
||||
}
|
||||
|
||||
console.log("=".repeat(80) + "\n");
|
||||
|
||||
// Only print once
|
||||
AuthHeaderInterceptor.intercept.implementation = this.intercept;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.log("[ERROR] " + e);
|
||||
console.log("[STACK] " + e.stack);
|
||||
}
|
||||
|
||||
// Call original
|
||||
return this.intercept(chain);
|
||||
};
|
||||
|
||||
console.log("[*] Hook installed!\n");
|
||||
|
||||
} catch (e) {
|
||||
console.log("[-] Failed: " + e);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user