アセンブリでポインタへのポインタを操作すると、混乱することは簡単です。引数として渡されたときに
argv
は真実argv
では、CHARまたはchar** argv
へのポインタへのポインタであり、それらのアイテムタイプへのポインタにCアレイ減衰であるため、「文字列の配列」またはそれcharへのポインタの配列であります。
これは、いずれかの文字列の文字にアクセスするために2つの逆参照が必要であり、1つはそのような文字列へのポインタにアクセスする必要があることを示しています。
パラメータは逆の順序でスタックに渡されCDECL規則を仮定すると、我々はargc
の値がebp+0ch
であることを持っている標準的なフレームポインタを設定し、標準的なプロローグを想定。
ebp
はポインタの意味を持ちますので、ebp+0ch
は別のポインタを得るためのポインタ算術に過ぎません。今度はargc
の値になります。
ebp+0ch
をC型にするとchar***
となるため、ポインタargv[1]
にアクセスするには2つの逆参照が必要です。
ESI
にargv[1]
を取得するためのコードは次のとおりです。
;typeof(ebp+0ch) = char***
mov esi, DWORD [ebp+0ch] ;1st defer, esi = argv, typeof(esi) = char**
mov esi, DWORD [esi+04h] ;2nd defer, esi = argv[1], typeof(esi) = char*
;Optional, Get a char
mov al, BYTE [esi] ;3rd defer, al = argv[1][0], typeof(al) = char
種類がチェック。
音が混乱しますか?
これらのポインタを描画しましょう!
The stack The memory
100ch | 2000h | argv 2000h | 2008h | argv[0]
1008h | 2 | argc 2004h | 2010h | argv[1]
1004h | yyyyyy | return address 2008h | file | argv[0][0..3]
1000h | xxxxxx | old frame pointer 200ch | .a\0\0 | argv[0][4..7]
2010h | -arg | argv[1][0..3]
EBP = 1000h 2014h | 1\0\0\0 | argv[1][4..7]
ebp+0ch
1000H + 0CH = 100CHであり、それはargv
値のアドレスです。
mov esi, DWORD [ebp+0ch]
はmov esi, DWORD [100ch]
と同じで、ESI
を2000hに設定します。
2000hはargv
の値であるため、アドレスはargv[0]
です。
argv[1]
のアドレスは4バイト先であり、したがって2000h + 04h = 2004hです。
mov esi, DWORD [esi+04h]
はmov esi, DWORD [2004h]
と同じで、2010hにはESI
と設定されています。
2010hは、文字列 "-arg1"のアドレスです。画像は上記CやC++のようなargv[argc]
準拠規格0
でなければならないこと
注私は左その画像のうち。
これらは同じではありません。最初のものは '*(*(ebp + 12)+4)'です.2番目のものは '*(ebp + 16)'だけです。逆参照を取り除くことはできません。 – Jester
@DanMašekに面倒なことには役に立たなかったことに感謝します。 – Eric
@Jester非常に感謝しています。私はそれについて考えます。 – Eric