フリーダをさまざまなアプリケーションにフックすることを学ぼうとしています。具体的には、Android アプリケーションに接続しようとしています。Appmon プロジェクトを使用しています。このプロジェクトには、HttpUrlConnection クラスから getInputStream および getOutputStream にフックする HTTPS.js スクリプトがあります。HTTPS.js スクリプトはメソッドを正常にフックしますが、HTTPS トラフィックが送信されると、表示されるデータは暗号化されます。
HTTPUrlConnectionに関する Android ドキュメントによると、URL.openconnection() メソッドが HTTPS URL を受け取ると、HTTPSUrlConnection オブジェクトが返されます。
HttpsURLConnectionの Android ドキュメントには、HttpURLConnection を拡張する抽象クラスであると記載されています。
パブリック抽象クラス HttpsURLConnection は HttpURLConnection を拡張します
Android ソース コードを検索したところ、HttpsURLConnection が抽象的であり、これも抽象的である DelegatingHttpsURLConnection によって拡張されていることがわかりました。DelegatingHttpsURLConnection はHttpsURLConnectionImplによって拡張されます
私は夢中になった
com.android.okhttp.internal.huc.HttpsURLConnectionImpl
これは成功しますが、データはまだ暗号化されています。ここにコードがあります
var HttpsURLConnection = Java.use("com.android.okhttp.internal.huc.HttpsURLConnectionImpl");
HttpsURLConnection.getInputStream.overloads[0].implementation = function() {
try {
methodURL = "";
responseHeaders = "";
responseBody = "";
var Connection = this;
var stream = stream = this.getInputStream.overloads[0].apply(this, arguments);
var requestURL = Connection.getURL().toString();
var requestMethod = Connection.getRequestMethod();
var requestProperties
methodURL = requestMethod + " " + requestURL;
if (Connection.getHeaderFields) {
var Keys = Connection.getHeaderFields().keySet().toArray();
var Values = Connection.getHeaderFields().values().toArray();
responseHeaders = "";
for (var key in Keys) {
if (Keys[key] && Keys[key] !== null && Values[key]) {
responseHeaders += Keys[key] + ": " + Values[key].toString().replace(/\[/gi, "").replace(/\]/gi, "") + "\n";
} else if (Values[key]) {
responseHeaders += Values[key].toString().replace(/\[/gi, "").replace(/\]/gi, "") + "\n";
}
}
}
var retval;
if (stream) {
var baos = ByteArrayOutputStream.$new();
var buffer = -1;
var BufferedReaderStream = BufferedReader.$new(InputStreamReader.$new(stream));
while ((buffer =stream.read()) != -1){
baos.write(buffer);
responseBody += String.fromCharCode(buffer);
}
BufferedReaderStream.close();
baos.flush();
retval = ByteArrayInputStream.$new(baos.toByteArray());
}
/* --- Payload Header --- */
var send_data = {};
send_data.time = new Date();
send_data.txnType = 'HTTPS';
send_data.lib = 'com.android.okhttp.internal.huc.HttpsURLConnectionImpl';
send_data.method = 'getInputStream';
send_data.artifact = [];
/* --- Payload Body --- */
var data = {};
data.name = "Request/Response";
data.value = methodURL + "\n" + requestHeaders + "\n" + requestBody + "\n\n" + responseHeaders + "\n" + responseBody;
data.argSeq = 0;
send_data.artifact.push(data);
send(JSON.stringify(send_data));
if(retval)
return retval;
return stream;
} catch (e) {
this.getInputStream.overloads[0].apply(this, arguments);
}
}
ところで、これが機能するようになったら、プル リクエストを送信する予定です。
Android のドキュメントには、HTTP リクエストを作成する方法の例があります。
URL url = new URL("https://wikipedia.org");
URLConnection urlConnection = url.openConnection();
InputStream in = urlConnection.getInputStream();
copyInputStreamToOutputStream(in, System.out);
これを読むと、getInputStream() メソッドを呼び出すだけでクリア テキスト ストリームが返されるはずですが、そうではないようです。
質問: HTTPS トラフィックからクリア テキスト データを取得するにはどうすればよいですか? 実際のデータではなく、ヘッダーが表示されます
10/13更新
表示されているデータが暗号化されておらず、単にエンコードされているだけなのだろうかと思っています。これは、私が受け取ったデータの抜粋です。
\\u001f\x8b\\b\\u0000\\u0000\\u0000\\u0000\\u0000\\u0004\\u0000\xed\xbd\\u0007`\\u001cI\x96%&/m\xca{\x7fJ\xf5J\xd7\xe0t\xa1\\b\x80`\\u0013$\xd8\x90@\\u0010\xec\xc1\x88\xcd\xe6\x92\xec\\u001diG#)\xab*\x81\xcaeVe]f\\u0016@\xcc\xed\x9d\xbc\xf7\xde{\xef\xbd\xf7\xde{\xef\xbd\xf7\xba;\x9dN\'\xf7\xdf\xff?\\\\fd\\u0001l\xf6\xceJ\xda\xc9\x9e!\x80\xaa\xc8\\u001f?~|\\u001f?\\"\\u001e\xff\\u001e\xef\\u0016ez\x99\xd7MQ-?\xfbhw\xbc\xf3Q\x9a/\xa7\xd5\xacX^
応答ヘッダーは、gzip でエンコードされていることを示します
Content-Encoding: gzip
Content-Length: 438
Content-Type: text/xml; charset=utf-8
送信リクエストには「Accept-Encoding: gzip」ヘッダーがありますが、このスタックオーバーフローの回答に関連しているのでしょうか。GZIPInputStream への呼び出しを追加しようとしましたが、アプリケーションは応答を好みません
更新 2 データをキャプチャすることができます。これは gzip の問題です。私が今直面している問題は、Android デバイス上のアプリケーションが GZIP された入力ストリームを期待していることです。Frida 内でデータを表示するには、GZIPInputStream を介してデータを実行する必要がありますが、再度圧縮してアプリに送信する方法はまだわかりません。GZIPOutputStream で簡単に試してみましたが、うまくいきませんでした。これが私の更新されたコードです。
HttpURLConnection.getInputStream.overloads[0].implementation = function() {
try {
methodURL = "";
responseHeaders = "";
responseBody = "";
var Connection = this;
if("gzip" == Connection.getContentEncoding())
{
var stream = InputStreamReader.$new(GZIPInputStream.$new(this.getInputStream.apply(this, arguments)));
}
else
{
var stream = InputStreamReader.$new(this.getInputStream.apply(this, arguments));
}
}
var requestURL = Connection.getURL().toString();
var requestMethod = Connection.getRequestMethod();
var requestProperties
methodURL = requestMethod + " " + requestURL;
if (Connection.getHeaderFields) {
var Keys = Connection.getHeaderFields().keySet().toArray();
var Values = Connection.getHeaderFields().values().toArray();
responseHeaders = "";
for (var key in Keys) {
if (Keys[key] && Keys[key] !== null && Values[key]) {
responseHeaders += Keys[key] + ": " + Values[key].toString().replace(/\[/gi, "").replace(/\]/gi, "") + "\n";
} else if (Values[key]) {
responseHeaders += Values[key].toString().replace(/\[/gi, "").replace(/\]/gi, "") + "\n";
}
}
}
var retval;
if (stream) {
var baos = ByteArrayOutputStream.$new();
var buffer = -1;
var BufferedReaderStream = BufferedReader.$new(stream);
while ((buffer =stream.read()) != -1){
baos.write(buffer);
responseBody += String.fromCharCode(buffer);
}
BufferedReaderStream.close();
baos.flush();
if("gzip" == Connection.getContentEncoding())
{
retval = GZIPOutputStream.$new(ByteArrayInputStream.$new(baos.toByteArray()));
}
else
{
retval = ByteArrayInputStream.$new(baos.toByteArray());
}
}
/* --- Payload Header --- */
var send_data = {};
send_data.time = new Date();
send_data.txnType = 'HTTP';
send_data.lib = 'com.android.okhttp.internal.http.HttpURLConnectionImpl';
send_data.method = 'getInputStream';
send_data.artifact = [];
/* --- Payload Body --- */
var data = {};
data.name = "Request/Response";
data.value = methodURL + "\n" + requestHeaders + "\n" + requestBody + "\n\n" + responseHeaders + "\n" + responseBody;
data.argSeq = 0;
send_data.artifact.push(data);
send(JSON.stringify(send_data));
if(retval)
return retval;
return stream;
} catch (e) {
this.getInputStream.overloads[0].apply(this, arguments);
}
}