Arvin Liu
Signartures
/ Behaviors
ML
MODEL
Predicted Scores
Benign / Malicious
Learn
Lookup hash
Sig A: Severity 5
Sig D: Severity 7
Maliciousness
Category
XGB LGBM
Behavior A: 11 times
Pointer
Saving Variables
int a = 5;
它在哪裡? | 它是什麼? | 它放了什麼? |
---|---|---|
第0個櫃子 (0x00) | 放學校的書的櫃子 | 國文課本。 |
第1個櫃子 (0x01) | 放輕小說的櫃子 | 涼宮春日的憂鬱。 |
第2個櫃子 (0x02) | 放本本的櫃子 | ????? |
編號 / 地址。
變數名稱。
具體來說是什麼。
(通常用十六進位, 0x 表示)
你可以想像程式的記憶體 (RAM)
有這樣的一個櫃子,並且附有編號
每個櫃子都會有三個屬性:
編號 0
編號 1
編號 2
它在哪裡? | 它是什麼? | 它放了什麼? |
---|---|---|
0x00000 |
int x | 7 |
0x00001 | 空的。 | 沒放東西。 |
0x00002 | 空的。 | 沒放東西。 |
找一個沒人用的櫃子。
讓別人知道 a 在哪裡。
把值放進去。
int a
5
int a = 5;
的流程
int main() {
int a = 5;
}
編譯 (Compile)
機器語言
用工具解析
組合語言
在 ebp - 4 的
位置上存放 5
movl 的指令:
movl src, dst
將 src 這個數值存入
dst 這個位置。
數值大小為 long (4 bytes)
這裡我使用 objdump
Address of "&" and dereference "*"
這裡說的運算子是什麼?
就相當於你說 -1 的 "-" 一樣,
是一種運算符號
它在哪裡? | 它是什麼? | 它放了什麼? |
---|---|---|
0x00000 | int x | 7 |
0x00004 | float a | 1.1 |
0x00008 | double b | 1.0 |
那麼 &x 就是 0x00000。
&
*
但... &x 的型態是什麼?
所以 & 可以把 int 變成 int* , * 可以把 int* 變回int
所以 & 可以把 float 變成 float* , * 可以把 float* 變回float
那麼你覺得 *(0x00000) 會是什麼?
它在哪裡? | 它是什麼? | 它放了什麼? |
---|---|---|
0x00000 | int x | 7 |
0x00004 | float a | 1.1 |
0x00008 | double b | 1.0 |
&
*
會編譯失敗。 因為0x00000是 int,不是 int*
一個是型態的一部分 (拿來當宣告用的),
一個是取值符號(拿來使用,當運算的)。
#include <iostream>
int main(){
int x=777;
std::cout << &x << std::endl;
//std::cout << *(int *)(0x7fffffffdc54) << std::endl;
std::cout << *&x << std::endl;
std::cout << &*&x << std::endl;
std::cout << *&*&x << std::endl;
//std::cout << *(0x7fffffffdc54) << std::endl; // CE
//std::cout << *x << std::endl; // CE
//std::cout << **&*&*&x << std::endl; // CE
}
/* Output -- Answers are here.
0x7fffffffdc54
777
777
0x7fffffffdc54
777
*/
除了練習上面的東西,觀察你變數的地址以外,
試試看 *(int *) 一個隨便給的數字會怎麼樣?
所以你們直接註解那行掉就可以囉!
* 小知識:現今電腦都有ASLR(位址空間組態隨機載入)保護機制,所以每一次執行的&x都不一樣。除非你把它關掉,你才可以預先知道&x是什麼。這邊看不懂沒關係,想了解可以自行google看看。
也就是 - 指標宣告
如果你要存int的地址,
那麼它型態就是 int * 。
它在哪裡? | 它是什麼? | 它放了什麼? |
---|---|---|
0x00000 | int x | 7 |
0x00008 | (int *) a | 0x00000 |
0x00010 | (int **) b | 0x00008 |
int x = 7;
int *a = &x;
int **b = &a;
std::cout << *a << std::endl;
*a = 5;
std::cout << **b << std::endl;
5
**b = x , *b =a , *a = x
int* a, b;
// 上下兩個等價
int *a;
int b;
// 所以宣告兩個指標要
int *a, *b;
所以一個byte 就是 00000000 ~ 11111111
通常bit都會八個一組,我們稱之為byte。
#include <iostream>
int is_admin = 0;
int ary[160];
int main(){
std::cout << sizeof(char) << std::endl;
std::cout << sizeof(int) << std::endl;
std::cout << sizeof(long long) << std::endl;
std::cout << sizeof(float) << std::endl;
std::cout << sizeof(int *) << std::endl;
std::cout << sizeof(double *) << std::endl;
}
// 1 4 8 4 8 8
#include <iostream>
int a;
int main(){
char c;
// 想辦法算出 &a - &c
}
hint : 我們知道指標的大小是 8 bytes,和longlong一樣。
answer : (long long) &a - (long long) &c
Segmentation Fault (會吃RE)
它在哪裡? | 它是什麼? | 它放了什麼? |
---|---|---|
0x00000 | int x | 7 |
0x00004 | 系統的祕密。 | 不給看&寫>< |
0x00008 | 還沒規劃的地方。 | ??????? |
*(int *)0x00004 或 *(int *)0x00008 因為這兩塊還沒規劃或者電腦不給你看,所以當你在*的時候就會出現記憶體區段錯誤。
(例如程式已停止回應。)
所以只要你 * 的位置是系統開給你的,例如宣告變數/陣列,那麼通常就不會出現RE。
int a = 5;
它在哪裡? | 它是什麼? | 它放了什麼? |
---|---|---|
0x00000 | 空的。 | 沒放東西。 |
0x00004 | 空的。 | 沒放東西。 |
0x00008 | int a | 5 |
之後程式自己的記憶體會長這樣子:
int a[4] = {0};
那這樣子呢?
它在哪裡? | 它是什麼? | 它放了什麼? |
---|---|---|
0xFFF00 | a[0] | 0 |
0xFFF04 | a[1] | 0 |
0xFFF08 | a[2] | 0 |
0xFFF0A | a[3] | 0 |
... |
大概會像這樣子:
int a[4] = {0};
編譯器會讓 a 和 &a 都會等於 0xFFF00, 但 *a 是 a[0]。
int a[4] = {0};
a[1] = 1;
追根究底,a[1]是什麼意思?
其實就是 *(a + 1) 的意思。(a 是類似int *,詳情請見上一頁)
那,a + 1 是什麼意思呢?
就是a這個指標的地址 + 1個int的大小。
根據上面的原則。寫a[1]或寫1[a] 都沒有關係喔!
因為 1 + a = a + 1。
一個型態的大小可以用sizeof(type)來看。例如sizeof(int)就會是4,表示4Bytes。
例如我們宣告 int ary[160];
但是題目的N可能會到10000,
因此你就會存取到ary[1600]。
它在哪裡? | 它是什麼? | 它放了什麼? |
---|---|---|
0x00000 | int x | 7 |
0x00004 | 系統的祕密。 | 不給看&寫>< |
0x00008 | 還沒規劃的地方。 | ??????? |
也就是你戳到0x00004/0x00008的時候,電腦就會因為安全因素讓你RE。
它在哪裡? | 它是什麼? | 它放了什麼? |
---|---|---|
0xF0000 | ary[0]在這裡。 | 0 |
0xF0004 | ary[1]在這裡。 | 0 |
.... | ... | ... |
0xF003C | ary[159]在這裡。 | 0 |
0xF0040 | 還沒用到 | ??? |
... | ... | ... |
0xF0400 | 系統的祕密>///< | 不給尼看>///< |
因為程式沒幫你開到0xF0400,
只要那邊有系統的祕密/還沒規劃,看了就會吃RE!
#include <iostream>
int ary[160];
int is_admin = 0;
int main(){
int i,x;
std::cin >> i >> x;
ary[i] = x;
if(is_admin){
std::cout << "How did you do that?\n";
}
}
你要輸入什麼才可以讓程式輸出
"How did you do that" 呢?
#include <iostream>
int is_admin = 0;
int ary[160];
int main(){
int i,x;
std::cin >> i >> x;
ary[i] = x;
if(is_admin){
std::cout << "How did you do that?\n";
}
}
你要輸入什麼才可以讓程式輸出
"How did you do that" 呢?
#include <iostream>
#include <cstring>
struct person{
char name[16];
int is_admin;
};
int main(){
char tmp[16];
struct person peipei;
peipei.is_admin = 0;
std::cin >> tmp ;
strcpy(peipei.name,tmp);
std::cout << "Hi! " << tmp << std::endl;
if(peipei.is_admin){
std::cout << "Wow! Peipei is so Dian!" << std::endl;
}
}
你要輸入什麼才可以讓程式輸出
"Wow! Peipei is so Dian!" 呢?
#include <iostream>
long long ary[160];
int is_user=0;
int is_admin=0;
int main(){
long long i,x;
std::cin >> i >> x;
ary[i] = x;
if(is_admin == 1){
std::cout << "Why Peipei is so dian?\n";
}
}
你要輸入什麼才可以讓程式輸出
"Why Peipei is so dian?" 呢?
例如 0x00000100000000 =
4294967296 (輸入4594967296即可。)
表示成二進位制後逆著寫。
詳情請查詢 little-endian
(big-endian 就是順著寫)
longlong 存成
????????10000000
is_user 存 ????????
is_admin 存 10000000
-> is admin 是 00000001 = 1 (逆著)
void f(int a){
a = 5;
}
int main(){
int a = 10;
f(a);
cout << a << endl;
}
void f(int *a){
*a = 5;
}
int main(){
int a = 10;
f(&a);
cout << a << endl;
}
//void f(int a[]){
void f(int *a){
a[1] = 5;
}
int main(){
int a[10]={0};
f(a);
std::cout << a[1] << std::endl;
}
void f(int &a){
a = 5;
}
int main(){
int a = 10;
f(a);
cout << a << endl;
}
void f(int a, int b){
int tmp = a ;
a = b;
b = tmp;
}
int main(){
int a = 10, b = 5;
f(a,b);
std::cout << a << "," << b << std::endl;
}
void f(int *a, int *b){
int tmp = *a ;
*a = *b;
*b = tmp;
}
int main(){
int a = 10, b = 5;
f(&a,&b);
std::cout << a << "," << b << std::endl;
}
void f(int &a, int &b){
int tmp = a ;
a = b;
b = tmp;
}
int main(){
int a = 10, b = 5;
f(a,b);
std::cout << a << "," << b << std::endl;
}