2021年7月18日日曜日

FRIDAでHTTPSENDREQUESTEXのLPINTERNET_BUFFERSA構造体の解析

ソースはこちら https://azurda.github.io/posts/lpinternet_buffersa_struct_parse/

この記事では、Windows APIのHttpSendRequestExAで使用されるLPINTERNET_BUFFERSA構造体の読み方について説明します。この投稿の背景には、StackOverflowの質問への回答があります。

この例では、アプリケーションを書く代わりにInternet Explorerを使用し、その上でFRIDAを使用しています。さて、HttpSendRequestExA/Wで使われている構造体の定義は以下の通りです。

typedef struct _INTERNET_BUFFERSA {
DWORD dwStructSize;
構造体_INTERNET_BUFFERSA *Next;
LPCSTR lpcszHeader;
DWORD dwHeadersLength;
DWORD dwHeadersTotal
LPVOID lpvBuffer;
DWORD dwBufferLength; DWORD dwBufferTotal; LPVOID lpvBuffer; DWORD dwBufferLength
DWORD dwBufferTotal; DWORD dwBufferLength; DWORD dwBufferTotal
DWORD dwOffsetLow;
DWORD dwOffsetHigh。
} internet_buffersa, *lpinternet_buffersa;

ここで注意すべき点は2つあります。1つ目は、最初のメンバーが構造体のサイズで、構造体の2つ目のメンバーが次の構造体へのポインタであることです。2つ目の注意点は、HttpSendRequestExWの代わりにLPCSTRを使うと、LPCWSTRになってしまうことです。

とはいえ、この構造体を解析するのはとても簡単で、ここには厄介なメンバーが3つだけあります。

  1. LPCSTRのサイズは、Process.pointerSize()に依存して変化します。
  2. LPVOID サイズは Process.pointerSize() に応じて変化します。
  3. *Next は次の構造体へのポインタなので、Process.pointerSize() に応じて変化します。

これを念頭に置いて、Process.pointerSize=4の32ビットプロセスの場合、オフセットは以下のようになります。

DWORD dwStructSize; // 0
struct _INTERNET_BUFFERSA *Next; // 4
LPCSTR lpcszHeader; // 8
DWORD dwHeadersLength; // 12
DWORD dwHeadersTotal; // 16
LPVOID lpvBuffer; // 20
DWORD dwBufferLength; // 24
DWORD dwBufferTotal; // 28
DWORD dwOffsetLow; // 32
DWORD dwOffsetHigh; // 36

計算が正しければ、dwStructSizeは32ビットプロセスの場合は40、16進数では0x28となります。以下のスクリプトは、32ビットプロセスのHttpSendRequestW構造体を正しくインターセプトすることができます。

Interceptor.attach(Module.getExportByName(null, "HttpSendRequestExW"), {)
	onEnter (args) {
		let internetBufferStruct = args[1];
		console.log("Struct size: " + internetBufferStruct.readPointer())を実行します。
		console.log("*Next: " + internetBufferStruct.add(Process.pointerSize).readPointer())を実行します。
		console.log("lpcszHeader: " + internetBufferStruct.add(Process.pointerSize * 2).readPointer()) を実行します。
		console.log("dwHeadersLength: " + internetBufferStruct.add(12).readPointer()) を実行します。
		console.log("dwHeadersTotal: " + internetBufferStruct.add(16).readPointer());
		let dwBufferLength = parseInt(internetBufferStruct.add(24).readPointer());
		console.log("lpvBuffer: " + internetBufferStruct.add(Process.pointerSize * 5).readCString(dwBufferLength)) を実行します。
		console.log("dwBufferLength: " + dwBufferLength");
		console.log("dwBufferTotal: " + internetBufferStruct.add(28).readPointer());
		console.log("dwOffsetLow: " + internetBufferStruct.add(32).readPointer());
		console.log("dwOffsetHigh: " + internetBufferStruct.add(36).readPointer());
	}
});

そして、これが32bitプロセスでの結果です。予測通り、最初のメンバーであるdwStructSizeは40(0x28)となりました。

64ビットプロセスでは、すべての pointer メンバーが生成するオフセットの違いだけを変更し、それに応じて他のメンバーを調整する必要があります。

0 件のコメント:

コメントを投稿

FRIDAでHTTPSENDREQUESTEXのLPINTERNET_BUFFERSA構造体の解析

ソースはこちら https://azurda.github.io/posts/lpinternet_buffersa_struct_parse/