C++のprivateプロパティを改竄する
前回、C++(gcc)のインスタンスの正体はインスタンス変数(プロパティ)を格納するための記憶領域だと言うことがわかったので、それを元にチョットお遊び。
ソース(Hoge9.cpp)
#include <stdio.h> class Hoge9 { private: int hoge; public: void printHoge(); }; void Hoge9::printHoge() { printf("hoge = %d\n", hoge); } int main(int argc, char *argv[]) { Hoge9 hoge9; hoge9.hoge = -1; hoge9.printHoge(); return 0; }
$ g++ -o Hoge9 Hoge9.cpp Hoge9.cpp: In function ‘int main(int, char**)’: Hoge9.cpp:5: error: ‘int Hoge9::hoge’ is private Hoge9.cpp:16: error: within this context
プライベートなプロパティにアクセスすんじゃねーよ的なことを言われる。
ソース改(Hoge9_2.cpp)
#include <stdio.h> class Hoge9 { private: int hoge; public: void printHoge(); }; void Hoge9::printHoge() { printf("hoge = %d\n", hoge); } int main(int argc, char *argv[]) { Hoge9 hoge9; *(int *)&hoge9 = -1; hoge9.printHoge(); // おまけ *(int *)&hoge9 = -2; hoge9.printHoge(); *(int *)&hoge9 = -3; hoge9.printHoge(); return 0; }
インスタンスの先頭アドレスはhogeプロパティのアドレスとなるので、そこに値を書きこむ。
コンパイル&実行
$ g++ -o Hoge9_2 Hoge9_2.cpp $ ./Hoge9_2 hoge = -1 hoge = -2 hoge = -3
改竄した値が表示されている。privateなプロパティを改竄することができた。
アクセス指定子はコンパイル時にしか効果を持たないようだ。
もうひとつ実験。今度は分割コンパイルを行ってみる。
Hoge10.h
#ifndef __HOGE10_H__ #define __HOGE10_H__ class Hoge10 { private: int hoge; public: void printHoge(); }; #endif // __HOGE10_H__
Hoge10.cpp
#include <stdio.h> #include "Hoge10.h" void Hoge10::printHoge() { printf("hoge = %d\n", hoge); }
これらからオブジェクトファイルを作成。
$ g++ -o Hoge10.o -c Hoge10.cpp
hoge プロパティを public へ変更したヘッダファイルを用意。
Hoge10_2.h
#ifndef __HOGE10_H__ #define __HOGE10_H__ class Hoge10 { public: int hoge; void printHoge(); }; #endif // __HOGE10_H__
メインプログラムを用意
Hoge10_main.cpp
#include "Hoge10_2.h" int main(int argc, char *argv[]) { Hoge10 hoge; hoge.hoge = 1; hoge.printHoge(); }
コンパイル&実行
$ g++ -o Hoge10_main.o -c Hoge10_main.cpp $ g++ -o Hoge10 Hoge10_main.o Hoge10.o $ ./Hoge10 hoge = 1
ヘッダファイルのアクセス指定子を変更するだけでprivateプロパティとしてコンパイルされたはずのオブジェクトファイル内のプロパティにアクセスできた。やはりアクセス指定子はコンパイル時にしかチェックされていないようだ。
まとめ
- private プロパティもポインタ経由で改竄可能
- アクセス指定子はコンパイル時にしかチェックされない