C++(の特殊関数)をアセンブリの目で見る


【声明:著作権所有、転載を歓迎します.商業用途には使用しないでください.連絡ポスト:[email protected]】ここで言う関数は主にinline関数、static関数を指します.inline関数は比較的特殊で、マクロの性質を持っていると同時に、コンパイラに関数検査をさせることができます.static関数も同様に特殊で、同じファイルの関数でしか使用できません.static関数がincludeファイルにある場合、このヘッダファイルは一度使用される限り、execファイルに再表示されます.今は理解が難しいかもしれませんが、ちょっと待ってください.例を挙げて説明します.最後に、置換のテクニックで関数ポインタを修正し、呼び出された関数を修正させることで、関数の定義が印象的になります.
(1)インライン関数
inline int add(int a, int b)
{
	return a + b;
}
では、この関数を適用するとき、どのようにコンパイルしますか?見てもいいですか?
0040114A   mov         eax,1
0040114F   add         eax,2
00401152   mov         dword ptr [ebp-4],eax

inline関数は特殊な関数です.関数のコンパイルを行うとき、コンパイラはインライン関数というコードを関数の要求に従ってフォーマットチェックします.しかし、コンパイルが実行コードを生成する過程で、コンパイラはこのコードをマクロの性質に従ってcallの関数にコピーします.したがって、call関数では、この呼び出しコードはcallの形式ではなく、文の形式に直接従っていることがわかります.しかし、このinline関数のコード行数は多すぎません.私たちがインラインする目的はcallの機会を減らすことです.
注意:
a)関数はコンパイル時にINLINE最適化スイッチをオンにする必要があり、【PROJECT】->「【setting】->「【C/C+」->「【optimizations】で、インライン拡張で2番目の項目を選択する
b)コンパイル時にエラーが発生する場合は、コンパイル命令/ZIを削除すればよい.その結果、ソースコードはワンステップデバッグできず、アセンブリレベルのワンステップデバッグしかできない
    
(2)static関数の属性
static int add(int a, int b)
{
	return a + b;
}
a)異なるソースファイルにこのようなadd関数があるとしたら?
異なるファイルで関数がstatic関数として宣言されている場合は関係なく、各static関数は各ファイルのみに使用され、multi definitionの問題はありません.
b)ヘッダファイルにこのようなstatic関数の宣言と定義がある場合?
ヘッダファイルにstatic関数が1つある場合は、この関数を呼び出す各ファイルがこのstatic関数を再コンパイルします.結果はa)と同じなので、自分でやってみて、static関数のアドレスを印刷して、add関数のアドレスが同じかどうかを見てみましょう.
    
(3)関数アドレスを変更する例
#include <windows.h>

int add(int a, int b)
{
	return a + b;
}

int sub(int a, int b)
{
	return a - b;
}

void set()
{
	HANDLE hProcess = GetCurrentProcess();
	DWORD pOldFlag = 0;
	BOOL result = 0;
	result = VirtualProtectEx(hProcess, (LPVOID)add, 0x10, PAGE_EXECUTE_READWRITE, &pOldFlag);
	if(result != 0)
	{
		printf("%d
", GetLastError()); } } void process() { char* n = (char*) add; char* t = (char*) sub; *n = 0xFF; *(n+1) = 0x25; *(int*)(n +2) = (int)&t; int data = add(3,2); assert(1 == data); return; }
簡単に説明します.上のコードには4つの関数が含まれています.add関数とsub関数は主にテストの代わりに使用されます.set関数はコードセグメントのアクセス属性を変更するコードです.process関数は私たちがテストして使用したコードです.実はこのコードの意味は難しくありません.目的はcall add関数で、実際にcallにあるのはsub関数であることを発見することです.では、私たちはどのようにして、肝心なのは2つの面です:(1)add関数コードセグメントのアクセス属性を修正します;(2)add関数の最初のバイトの内容を変更するには、関数addの内容をjmp subに変更する必要があります.属性を変更してから、内容を変更します.
【予告:次のブログは主にclassメモリ分布の問題に関連しています】