アドレス
 ストレートにいうと、読み書きする場所です。大抵は、頭に0xを付けた16進数もしくは10進数で書きますが、特殊な演算を必要とする場合、「アドレスコーディング」と呼ばれる計算式で書くことも出来ます。
0x400000
4194304
_ 0x400 * 52 +10
_ 0x400 * (52 +10)
_ [: 0x400000 :]
_ [_ [: 0x400000 :] _]
 上から2行はただの数値ですので、改めて説明する必要はないと思います。どちらもアドレスは0x40000になります。
難解度「AA」
 問題はその下、アンダーバー(_)ではじまる「アドレスコーディング」を用いた計算式です。アドレスコーディングでは、数値(オペランド)の他に演算子を含むことができ、すべての演算子を処理した結果(必ず数値になる)が、実際に読み書きするアドレスになります。
演算子※ 説明 ※
+ 加算演算子。算術演算子の一つ。前後2つのオペランドを加算します。
_ 0x400+0x20
※この結果は0x0420 です。
- 減算演算子。算術演算子の一つ。前のオペランドから後ろのオペランドを減算します。
_ 0x400-0x20
※この結果は0x03E0 です。
* 乗算演算子。算術演算子の一つ。前後2つのオペランドを乗算(掛け合わせる)します。
_ 0x400*0x20
※この結果は0x8000 です。
/ 除算演算子。算術演算子の一つ。前のオペランドを後ろのオペランドで除算した(割った)商を返します。
_ 0x400/0x20
※この結果は0x20 です。
% 剰余算演算子。算術演算子の一つ。前のオペランドを後ろのオペランドで除算した(割った)剰余(余り)を返します。
_ 0x400%0x20
※この結果は0 です。
idiv 符号付除算演算子。算術演算子の一つ。オペランドを符号付整数として演算し、前のオペランドを後ろのオペランドで除算した(割った)商を返します。
_ 1024 idiv -32
※この結果は0xFFFFFFE0(-32) です。
imod 符号付剰余算演算子。算術演算子の一つ。オペランドを符号付整数として演算し、前のオペランドを後ろのオペランドで除算した(割った)剰余(余り)を返します。
_ 1024 imod -10
※この結果は0xFFFFFFFC(-4) です。
& ビットごとのAND演算子。算術演算子の一つ。前後2つのオペランドでビットごとに論理積を取ります。
_ 0x400&0x20
※この結果は0 です。
^ ビットごとのXOR演算子。算術演算子の一つ。前後2つのオペランドでビットごとに排他論理和を取ります。
_ 0x421^0x20
※この結果は0x401 です。
| ビットごとのOR演算子。算術演算子の一つ。前後2つのオペランドでビットごとに論理和を取ります。
_ 0x400|0x20
※この結果は0x420 です。
~ ビットごとのNOT演算子。拡張された算術演算子の一つ。ビットを反転(論理否定)させます。
_ ~0x430
※この結果は0xFFFFFBCF です。
<< 左論理シフト。拡張された算術演算子の一つ。前のオペランドを後ろのオペランドで左に論理シフトした値を返します。
_ 0x400<<4
※この結果は0x4000 です。
>> 右論理シフト。拡張された算術演算子の一つ。前のオペランドを後ろのオペランドで右に論理シフトした値を返します。
_ 0x400>>4
※この結果は0x40 です。
sar 右算術シフト。拡張された算術演算子の一つ。前のオペランドを後ろのオペランドで右に算術シフトした値を返します。
_ 0x80000000 sar 4
※この結果は0xF8000000 です。シフトした分は符号ビットである最上位の1ビットで補完します。
rol 左ローテート。拡張された算術演算子の一つ。前のオペランドを後ろのオペランドで左にローテートした値を返します。
_ 0x12348678 rol 4
※この結果は0x23486781 です。シフトした分は下位ビットへ移動します。
ror 右ローテート。拡張された算術演算子の一つ。前のオペランドを後ろのオペランドで右にローテートした値を返します。
_ 0x12348678 ror 4
※この結果は0x81234867 です。シフトした分は上位ビットへ移動します。
! 論理否定。後ろのオペランドが0なら、1 を返し、それ以外なら0 を返します。
_ !0x400
※この結果は0 です。
< 関係演算子の一つ。前のオペランドが後ろのオペランドより小さいなら、1 を返し、それ以外なら0 を返します。
_ 0x400<0x20
※この結果は0 です。
> 関係演算子の一つ。前のオペランドが後ろのオペランドより大きいなら、1 を返し、それ以外なら0 を返します。
_ 0x400>0x20
※この結果は1 です。
<= 関係演算子の一つ。前のオペランドが後ろのオペランド以下なら、1 を返し、それ以外なら0 を返します。
_ 0x400<=0x20
※この結果は0 です。
>= 関係演算子の一つ。前のオペランドが後ろのオペランド以上なら、1 を返し、それ以外なら0 を返します。
_ 0x400>=0x20
※この結果は1 です。
lt 関係演算子の一つ。オペランドを符号付整数として比較し、前のオペランドが後ろのオペランドより小さいなら、1 を返し、それ以外なら0 を返します。
_ 0x400 lt -1
※この結果は0 です。
gt 関係演算子の一つ。オペランドを符号付整数として比較し、前のオペランドが後ろのオペランドより大きいなら、1 を返し、それ以外なら0 を返します。
_ 0x400 gt -1
※この結果は1 です。
le 関係演算子の一つ。オペランドを符号付整数として比較し、前のオペランドが後ろのオペランド以下なら、1 を返し、それ以外なら0 を返します。
_ 0x400 le -1
※この結果は0 です。
ge 関係演算子の一つ。オペランドを符号付整数として比較し、前のオペランドが後ろのオペランド以上なら、1 を返し、それ以外なら0 を返します。
_ 0x400 ge -1
※この結果は1 です。
== 等値演算子の一つ。前後2つのオペランドが等しいときは1 を、そうでなければ0 を返します。
_ 0x400==0x20
※この結果は0 です。
!= 等値演算子の一つ。前後2つのオペランドが等しくなければ1 を、等しければ0 を返します。
_ 0x400!=0x20
※この結果は1 です。
&& 論理AND演算子。論理演算子の一つ。前後のオペランドが 0 以外の値のとき、1 を返します。どちらかのオペランドが 0 のときは、0 を返します。なお前のオペランドが 0 のときは、後ろのオペランドを評価しません。
_ 0x400&&0x20
※この結果は1 です。
|| 論理OR演算子。論理演算子の一つ。前後のオペランドが 0 のとき、0 を返します。どちらかのオペランドが 0 以外のときは、1 を返します。前のオペランドが 0 以外のときは、後ろのオペランドを評価しません。
_ 0x400||0x20
※この結果は1 です。
条件式 ? 真式 : 偽式 条件演算子(三項演算子)。「条件式」を評価し、その結果が 0 以外のときは「真式」を、それ以外のときは「偽式」を評価します。
_ 0x400 != 0 ? 1 : 0
※この結果は1 です。
※真式・偽式のうち片方のみ評価します。そのため代入を含む式であっても片方のみ実行します。
[: :]
難解度「AA+」
ポインタ変換演算子。括ったオペランドをポインタと見なし、そのアドレスにある4バイトの数値を返します。
_ [: 0x400000 :]
※この結果は、アドレス0x400000 にある4バイトの数値です。

なお、取得を4バイト未満にしたい場合は、閉じ括りにバイト数を挟むことで可能になります。
_ [: 0x400000 :3]
_ [: 0x400000 :2]
_ [: 0x400000 :1]
※[: :N] のサイズ(N)は1〜8バイトまでです。

SpoilerALに確保されたメモリにアクセスする場合は [: :L] を使用します。
_ [: 0x400000 :L]
_ [: 0x400000 :L3]
_ [: 0x400000 :L2]
_ [: 0x400000 :L1]
* 間接演算子。[: :]と同等でプログラミング言語の書式に合わせたものです。
[: :] は *( ) に置き換える事もできます。
_ *0x400000
※この結果は、アドレス0x400000 にある4バイトの数値です。
※乗算の*記号との違いは、単項演算子であり、かつ前置演算子である事です。
※認識方法としては、演算子が構文の先頭にあるか、もしくは前方が演算子で後置ではない場合、間接演算子と認識します。
[. .] オフセット演算子。括ったオペランドに、[replace]によるオフセット値を加算した値を返します。
_ [. 0x400000 .]
※この結果は、0x400000 に[replace]のオフセット値を加算した数値です。オフセット値がないなら、0x400000 がそのまま使われます。
[_ _] アドレス補正演算子。括ったオペランドに、[adjustment]によるアドレス補正をかけた値を返します。
_ [_ 0x400000 _]
※この結果は、0x400000 にアドレス補正をかけた数値です。アドレス補正属性がないなら、0x400000 がそのまま使われます。
[. .] オフセット演算子。括ったオペランドに、[replace]によるオフセット値を加算した値を返します。
_ [. 0x400000 .]
※この結果は、0x400000 に[replace]のオフセット値を加算した数値です。オフセット値がないなら、0x400000 がそのまま使われます。
[~ ~] エンディアン反転演算子。括ったオペランドに、4バイト単位でエンディアン反転を行った値を返します。
_ [~ 0xFF00AA55 ~]
※この結果は、0x55AA00FF です。

なお、反転するバイト範囲を4バイト未満にしたい場合は、閉じ括りにバイト数を挟むことで可能になります。
_ [~ 0x400000 ~3]
_ [~ 0x4000 ~2]
※バイト単位での反転なので、1バイト用はありません。
※[~ ~N] のサイズ(N)は2〜8バイトまでです。
MName:: モジュールアドレス演算子。次に続く文字オペランドをモジュール名に持つモジュールの、開始アドレスを返します。
_ MName::GDI32.dll
※この結果は、対象プロセスにおけるモジュール「GDI32.dll」の開始アドレスです。

なお、オペランドの連続は許されていないので、「MName::GDI32.dll 0x400」といった書き方はあり得ませんが、読みにくいようなら、()による表記で対応しても良いでしょう。
_ (MName::GDI32.dll) + 0x400
_ 200 - (MName::KERNEL32.dll) + 0x20
※モジュール名は、大文字小文字を区別しません。
MName::モジュール名:: エクスポート関数を取得するオプショナル引数。次に続く文字オペランドのエクスポート関数のアドレスを返します。
_ MName::user32.dll::MessageBoxA
※この結果は、対象プロセスにおけるモジュール「user32.dll」がエクスポートする関数「MessageBoxA」の絶対アドレスです。
※関数名は大文字小文字を区別します。

なお、序数も扱えるので無名の関数も取得できます。
_ MName::user32.dll::1500
※この結果は、対象プロセスにおけるモジュール「user32.dll」がエクスポートする関数の序数「1500」の絶対アドレスです。
※序数に変数を使う場合は関数名と区別するため ( ) で括り「MName::user32.dll::($Val)」などと記述する必要があります。
MName::モジュール名:=
MName::モジュール名:+
セグメントアドレスを取得するオプショナル引数。次に続く文字オペランドのセグメントのアドレスを返します。
_ MName::nul:=.data
※この結果は、対象プロセスにおける「.data」セグメントのアドレスです。
※セグメントは大文字小文字を区別します。

セグメントアドレスにサイズを加算したアドレスも取得できます。
_ MName::nul:+.data
※この結果は、対象プロセスにおける「.data」セグメントにサイズを加算したアドレスです。
※終端(先頭 + サイズ - 1)ではなく、「.data」として初期化された領域の外(先頭 + サイズ)で空き領域となる事もあります。
HNumber:: ヒープアドレス演算子。次に続く数値オペランド番目のヒープの、開始アドレスを返します。
_ HNumber::1
※この結果は、対象プロセスにおける1番目のヒープ(Heap1)の開始アドレスです。
※ヒープ番号は、1から始まります。
Cast32:: 32bitキャスト。次に続くオペランドを32bitにキャストします。
_ Cast32::0x123456789ABCDEF0
※この結果は、0x9ABCDEF0 です。
Cast64:: 64bitキャスト。次に続くオペランドを64bitにキャストします。
_ Cast64::0xFFFFFFFF + 1
※この結果は、0x100000000 です。
※値は変わりませんが後続の演算を64bitで行います。
I1toI4:: 符号付32bitキャスト(下位8bitからの符号拡張)。次に続くのオペランドの下位8bitを32bitにキャストします。
キャスト後は演算の種類で符号ビットを扱います。
_ I1toI4::0xFF
※この結果は、0xFFFFFFFF です。
※符号付24bitなどは「(($Val << (32 - 24)) sar (32 - 24))」などと演算を用いる方法があります。
I2toI4:: 符号付32bitキャスト(下位16bitからの符号拡張)。次に続くのオペランドの下位16bitを32bitにキャストします。
キャスト後は演算の種類で符号ビットを扱います。
_ I2toI4::0xFFFF
※この結果は、0xFFFFFFFF です。
※符号付24bitなどは「(($Val << (32 - 24)) sar (32 - 24))」などと演算を用いる方法があります。
I4toI8:: 符号付64bitキャスト。次に続くのオペランドを64bitにキャストします。
他の符号拡張とは違い後続の演算を64bitで行います。
キャスト後は演算の種類で符号ビットを扱います。
_ I4toI8::-1
※この結果は、0xFFFFFFFFFFFFFFFF です。
Memory:: 次に続くIDのメモリアドレスを返します。メモリ確保は 《5-メモリ確保》を参照。
_ Memory::0
※この結果は、対象のプロセスに確保されたのメモリアドレスです。
_L Memory::0
※この結果は、SpoilerALに確保されたのメモリアドレスです。SpoilerALにアクセスする場合は先頭に「L」を付ける必要があります。
※失敗した場合はゼロを返します。
strlen:: 次に続くオペランドのアドレスに存在する文字列の長さを返します。
_ strlen::0x400000
※この結果は、0x400000 のアドレスにある文字列のバイト数です。ナルターミネーターは含みません。
※演算結果を対象にする場合は、括弧で囲み strlen::(演算) と記述するか変数を使う必要があります。
wcslen:: 次に続くオペランドのアドレスに存在するUNICODE文字列の長さを返します。
_ wcslen::0x400000
※この結果は、0x400000 のアドレスにあるUNICODE文字列の文字数です。ナルターミネーターは含みません。
※演算結果を対象にする場合は、括弧で囲み wcslen::(演算) と記述するか変数を使う必要があります。
BitScanForward:: 次に続くオペランドの最下位ビットから最上位ビットの順に1にセットされているビットを検索し、最下位ビットを0番目とするインデックスを返します。
_ BitScanForward::0xFFFF0000
※この結果は、16 です。
※見つからない(オペランドに0を指定した)場合は 0xFFFFFFFF を返します。
※演算結果を検索する場合は、括弧で囲み BitScanForward::(演算) と記述するか変数を使う必要があります。
BitScanReverse:: 次に続くオペランドの最上位ビットから最下位ビットの順に1にセットされているビットを検索し、最下位ビットを0番目とするインデックスを返します。
_ BitScanReverse::0x0000FFFF
※この結果は、15 です。
※見つからない(オペランドに0を指定した)場合は 0xFFFFFFFF を返します。
※演算結果を検索する場合は、括弧で囲み BitScanReverse::(演算) と記述するか変数を使う必要があります。
$変数名 擬似変数。演算子ではなくオペランドの一種です。次に説明する変数代入と組み合わせて使います。「変数名」の指す変数の値を返します。
_ $tmp + 2
※変数「tmp」が一度も代入されていないため、$tmpは0として扱われ、この結果は2になります。
=> 変数名 変数代入演算子 (右辺代入)。「=>」に続く変数名の変数を定義し、前のオペランドの値を代入します。ただし、$Valは予約語変数のため、ここでは使用できません。
_ 0x400 => tmp; $tmp+0x10;
※この結果は、0x410 です。
なお、例中の「;」については、次節「アドレスコーディングの分割」を参照してください。
変数名 = オペランド
$変数名 = オペランド
変数代入演算子 (左辺代入)。「=」の前の変数名の変数を定義し、後ろのオペランドの値を代入します。
_ $tmp = 0x400; $tmp + 0x10;
※この結果は、0x410 です。

_ $tmp = 0x410;
※この結果は、0x410 です。

++$変数名 前置インクリメント演算子。算術演算子の一つ。演算子の後ろの変数を1加算し演算後の値を返します。
_ $tmp1 = 0x400; $tmp2 = ++$tmp1; $tmp2
※$tmp1の値は0x401で、この結果は0x401です。
$変数名++ 後置インクリメント演算子。算術演算子の一つ。演算子の前の変数を1加算し演算前の値を返します。
_ $tmp1 = 0x400; $tmp2 = $tmp1++; $tmp2
※$tmp1の値は0x401で、この結果は0x400です。
--$変数名 前置デクリメント演算子。算術演算子の一つ。演算子の後ろの変数を1減算し演算後の値を返します。
_ $tmp1 = 0x400; $tmp2 = --$tmp1; $tmp2
※$tmp1の値は0x3FFで、この結果は0x3FFです。
$変数名-- 後置デクリメント演算子。算術演算子の一つ。演算子の前の変数を1減算し演算前の値を返します。
_ $tmp1 = 0x400; $tmp2 = $tmp1--; $tmp2
※$tmp1の値は0x3FFで、この結果は0x400です。
$変数名 += オペランド
$変数名 -= オペランド
$変数名 *= オペランド
$変数名 /= オペランド
$変数名 %= オペランド
$変数名 &= オペランド
$変数名 |= オペランド
$変数名 ^= オペランド
$変数名 <<= オペランド
$変数名 >>= オペランド
複合代入演算子。演算と代入を行い演算後の値を返します。
演算子の優先順位が代入と同列である事に注意してください。
各演算子の優先順位は、高い順に並べると
++ (後置), -- (後置)
MName:: HNumber:: Cast32:: Cast64:: I1toI4:: I2toI4:: I4toI8:: Memory:: strlen:: wcslen:: BitScanForward:: BitScanReverse::
++ (前置), -- (前置), + (単項プラス), - (単項マイナス), !, ~, * (間接演算子)
*, /, %, idiv, imod
+, -
<<, >>, sar, rol, ror
<, >, <=, >=, lt, gt, le, ge
==, !=
&
^
|
&&
||
?: (条件演算子)
=>, =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=
[: :], [~ ~], [. .], [_ _]
です。同順位の演算子は、前にある方から処理されます。なお、括弧()を使って、演算の順位を変えることも出来ます。
 多くの場合アドレスコーディングを使うことはありませんが、一部特殊な変換を必要とするプロセスの場合、その威力を発揮します。必要になってから学んでもいいかもしれません(笑)

 ※一括系等でアドレスを羅列したリストの場合、ちょっと注意が必要です。項目自体のアドレスには[replace]のオフセット加算やアドレス補正が適用されますが、リスト内のアドレスは、数値変換のみ行われます。リスト内のアドレスにも変換を行う場合は、アドレスコーディングを使って明示してください。

なお、主にアドレス補正属性等で使用する手ですが、以下のように対象プロセスのヒープやモジュールの開始アドレスを示す指定法もあります。
heap1
module1
heapNは、N番目のヒープの開始アドレスを指します。
moduleNは、N番目のモジュールの開始アドレスを指します。
ともに、添字Nは1から始まります。


難解度「AA+」
アドレスコーディングの分割
 変数代入演算子の説明で使用していますが、アドレスコーディングはセミコロン(;)単位で分割することが出来ます。この場合、最後の処理結果が採用されるわけですが、今のところ変数代入演算子を使わない限り、利用価値はないと思われます。
 もうひとつ、アドレスコーディングは'_'から始まると書きましたが、@から始める記述法もあります。この場合、別ファイルにアドレスコーディングを記述できます。書式は
@チェインファイル名
となります。(ファイル指定の詳細は、《C-ファイル指定》を参照。)
 このようにして呼び出されるチェインファイル内には、複数行に渡ってアドレスコーディングを記述できます。(最初に'_'は不要)
[subject]体力:calc,@チェインファイル,0,99

チェインファイル.CHN
[:0x400000:] + [:0x400010:] => フラグ;
[: $フラグ :] + $フラグ;
 アドレスコーディング部分が長くなりすぎる場合などに利用すると、分かりやすく記述できるでしょう。




ねくすと せくしょん⇒

≪せくしょん ばっく