1

C、特にStackの低レベルメモリマネージャを理解しようとしています。言われたように、関数が呼び出されると、リターンアドレスがスタックにプッシュされました。その後、ローカル変数が配置されます。

そこで、これを調査するための小さなプログラムを作成します。これが私のプログラムです:

#include <stdio.h>

void TestStack();

void DoTestStack() {
    char x1 = 1;
    char x2 = 2;
    char x3 = 3;
    char x4 = 4;
    char *x = &x4;

    printf("TestStack: %08X\n", (&TestStack));
    printf("\n");

    int i;
    x = &x4;
    for(i = 0; i < 32; i++)
        printf("%02d: %08X : %08X\n", i, *(x + i), *(x - i));

    printf("\n");
    printf("x1: %02X\n", x1);
    printf("x2: %02X\n", x2);
    printf("x3: %02X\n", x3);

    printf("DONE!!!\n");
}

void TestStack() {
    DoTestStack();
}

void main() {
    TestStack() ;
}

基本的に、位置x4が配置される前後のすべてのメモリを調査します。これは、差出人住所の位置を十分にカバーしているはずです。

しかし、差出人住所に似たバイトがまったく見つからないようです。

これが私の結果です:

TestStack: 08048B49

00: 00000004 : 00000004
01: 00000003 : FFFFFFBF
02: 00000002 : FFFFFFAC
03: 00000001 : FFFFFFED
04: 00000004 : 0000001C
05: FFFFFFC3 : 00000000
06: FFFFFFB9 : 00000000
07: 00000000 : 00000000
08: FFFFFFF4 : 00000008
09: FFFFFFBF : 00000000
10: FFFFFFB9 : FFFFFF90
11: 00000000 : FFFFFFBD
12: 00000038 : 00000020
13: FFFFFFED : 00000000
14: FFFFFFAC : 00000000
15: FFFFFFBF : 00000000
16: 00000054 : 00000000
17: FFFFFF8B : 00000000
18: 00000004 : FFFFFFFF
19: 00000008 : 00000000
20: 00000045 : 00000008
21: 00000073 : 00000000
22: FFFFFFA7 : 00000000
23: 00000000 : 00000000
24: 00000020 : 00000017
25: FFFFFFBD : 00000008
26: FFFFFF90 : 00000004
27: 00000000 : FFFFFF8C
28: 00000048 : FFFFFFCF
29: FFFFFFED : 00000008
30: FFFFFFAC : 00000004
31: FFFFFFBF : FFFFFF8A

x1: 01
x2: 02
x3: 03
DONE!!!

ここで何が欠けていますか?誰か説明してもらえますか?

とにかく私はUbuntu9.10を使用しています。

前もって感謝します。:-D

4

3 に答える 3

6

個々の文字を見て、それらを 32 ビット整数にキャストしているため、混乱します。戻りアドレスは、次の 4 行の最下位バイトにあります。

16: 00000054 : 00000000
17: FFFFFF8B : 00000000
18: 00000004 : FFFFFFFF
19: 00000008 : 00000000

つまり、返信アドレスは 0x08048b54 です。

代わりにこれを試してください:

uint32_t *x;
x = (uint32_t *)&x4;
for(i = 0; i < 32; i++)
    printf("%02d: %08X : %08X\n", i, *(x + i), *(x - i));
于 2009-10-03T10:58:15.050 に答える
4

この行で:

    printf("%02d: %08X : %08X\n", i, *(x + i), *(x - i));

ポインターはx文字ポインターであり、逆参照後に符号拡張付きの整数に昇格され、ビット 7 の値に応じてすべての出力値が 000000xx または FFFFFFxx のいずれかになります。

int代わりに、ポインターの代わりにポインターを使用してスタック値をスキャンすることをお勧めしcharます。

于 2009-10-03T10:55:40.280 に答える
1

これがどのように機能するかを知りたい場合は、アプリケーションをデバッガーで実行することをお勧めします。何が起こっているのかを理解するのは本当にがらくたです。

どのデバッガーでも問題ありませんが、windbg を最もよく知っているので、Greg が提案したように、int* が必要なように、コードのわずかに変更されたバージョンで開始するためのいくつかのポインターを次に示します。

変化する:

 char *x = &x4;

に:

 int *x = &i;

消去:

 x = &x4;

MOVE(最初の変数、x1 の前):

 int i;

新しい変更 (非常に読みやすく、以前のように (xi) を実行すると、ランダム/現在範囲内の値ではありません):

printf("%02d: %08x : %08x\n", i, x + i, *(x + i));   

この変更により、スタック フレーム アドレスと値が効果的に表示されます。

windbg で、呼び出し、メモリ、スレッド、コマンド ウィンドウをすべて表示できるようにします。C コードをコンパイラでコンパイルします。私は MSVC を使用し (無料で試用できます)、「Visual Studio 20## コマンド プロンプト」で「cl /Zi your.c」を指定してコンパイルします。Windbg (Windows 用のデバッグ ツール) をロードし、Ctrl+E を押すか、「実行可能ファイルを開く」を使用します。

Calls、Locals、Memory、Threads、および Command のすべてのウィンドウを一度に表示できるように、次のウィンドウをロードします。

コマンド ウィンドウで、"bu DoTestStack" を使用して DoTestStack にブレークポイントを設定します。

「g」コマンドでデバッグを開始します。

ブレークポイントに到達したら、"p" を使用してシングル ステップを実行します。ソースもポップアップ表示されます。または、for ループで実行された後、アプリケーションの出力を確認して、Windbg に戻ります。メモリ ウィンドウを開き、「i」のアドレス タイプの「ポインターとシンボル」に設定します。コンパイル (/Zi) からのデバッグ情報が含まれている必要があり、「ポインターとシンボル」のリストが表示されます。 i のアドレスへのポインタ。

出力はテスト コードと同じになるはずです (提案した変更を行った後)。p を押し続けると、メモリ ウィンドウで i の値が実行ごとに変化することを確認できますが、printf として現在、他の値を出力しています。出力の元の「0」に表示されます;)。

または、windbg コマンドddsを使用することもできます (for ループの途中にあるため、i の値は 0xb であることに注意してください)。

0:000> dds i
0018ff24  0000000b
0018ff28  02586bf9
0018ff2c  0018ff24
0018ff30  0018ff38
0018ff34  00401118 a!TestStack+0x8 [c:\temp\a.c @ 33]
0018ff38  0018ff40
0018ff3c  00401128 a!main+0x8 [c:\temp\a.c @ 35]
0018ff40  0018ff88
0018ff44  00401435 a!__tmainCRTStartup+0xf8 [f:\dd\vctools\crt_bld\self_x86\crt\src\crt0.c @ 257]
0018ff48  00000001
0018ff4c  003c1e48

これは、変更されたテスト コードと同じです (シンボル サポートがないことを除く)。

00: 0018ff24 : 00000000
01: 0018ff28 : 02586bf9
02: 0018ff2c : 0018ff24
03: 0018ff30 : 0018ff38
04: 0018ff34 : 00401118
05: 0018ff38 : 0018ff40
06: 0018ff3c : 00401128
07: 0018ff40 : 0018ff88
08: 0018ff44 : 00401435
09: 0018ff48 : 00000001
10: 0018ff4c : 003c1e48
于 2009-10-03T11:54:41.487 に答える