身内に向けてhackmdで書いた記事を移植
CTFをやってるとReverseの問題でデコンパイラのGhidraを使う機会があります。あるプログラムを読ませたときにこんなコードが返ってきました
local_28 = 0x6e34637b67616c66;
local_20 = 0x594f5345485f7427;
for (j = 0; j < 16; j = j + 1) {
if (param_1[j] != *(char *)((long)&local_28 + (long)j)) {
星だらけで認識しにくい...
普段Cだのポインタを使う言語で開発しないのでちょっとすらすら読むには復習が必要そうです
&演算子
&てなんだっけと思ってググったらどうやらアドレス取得演算子らしいです。
すなわち&local_28
てのはlocal_28
変数の開始アドレスを返すわけだな。そんでもってそれをlong型にキャストしていると。
ポインタとデリファレンス
思い出してきたけど一応メモっておきましょう。
int *a
ていうのは単純にポインタだったはずです。
逆に、
*a
みたいなのはポインタの指すメモリの実値を取得するやつだったはず。これはデリファレンスというらしい。
つまり?
local_28 = 0x6e34637b67616c66;
local_20 = 0x594f5345485f7427;
for (j = 0; j < 16; j = j + 1) {
if (param_1[j] != *(char *)((long)&local_28 + (long)j)) {
こいつについて考え直しましょう。
アセンブラを読む限りlocal_28
とlocal_20
はどうやらスタック上で連続しているようです。
よんでいくと...
-
local_28
のアドレスを取得 - アドレスに対してfor文で1ずつ加算
- 1, 2で得られたアドレスをchar型のポインタとしてキャスト
- キャストしてできたポインタをデシリアライズ
これによってlocal_28
から16バイト分を1バイトずつ取り出してcharとしてparam_1
と比較しているようです。
たしかにアセンブラをそのまま起こすとこんなかんじになっちゃいそう
ポインタと配列
今回の復習でポインタと配列の関係も理解しました。
a[1]
みたいなのは
*((long)&a + (long) 型のサイズ*index)
みたいな感じであらわせるわけですね