Assembly cho script kiddie part 1
Assembly cho script kiddie part 1
Assembly là gì?
Lập trình Assembly
Kiểu dữ liệu cơ bản
- BYTE: 8 bit, char
- WORD: 16 bit, char
- DWORD: 32 bit, integer
- QUADWORD: 64 bit, integer
- DOUBLE QUADWORD: 128 bit
Thanh ghi cờ thông dụng
- CF: carry flag
- SF: sign flag
- ZF: zero flag
- OF: overflow flag
- PF: parity flag
Operand
- immediate: làm với số. ví dụ
add rax, 14
- registry: làm với thanh ghi ví dụ
mov rax, rbx
- memory: làm việc với vùng nhớ ví dụ
or rax, [rbx + rsi*8]
Các thanh ghi thông dụng
Ngoài ra RIP: pointer register
Bài tập chuyển từ mã asm sang C
1 2 3 4 5 6 7 8 9 10 11 12 13
mov rax,42 | rax = 42 imul r12,-47 | r12 *=-47 shl r15,8 | r15 = r15 << 8 xor ecx,80000000h | ecx ^= 80000000h sub r9b,14 | r9b -= 14 mov rax,rbx | rax = rbx add rbx,r10 | rbx += r10 mul rbx | rbx:rax = rax*rbx and r8w,0ff00h | r8w &= 0ff00h mov rax,[r13] | rax += *r13 sub qword ptr [r8],17 | *(long long*)r8 -= 17 shl word ptr [r12],2 | *(short*)r12<<=2 or rcx,[rbx+rsi*8] | rcx |= *(rbx+rsi*8)
Memory addressing
Khi một lệnh x86-64 muốn truy cập vào địa chỉ ô nhớ thay vì truy cập qua thanh ghi, nó sẽ truy cập qua 4 thành phần.
EffectiveAddress = BaseReg + IndexReg * ScaleFactor + Disp
Trong đó base register có thể là bất cứ thanh ghi nào, index register là bất kì thanh ghi nào trừ RSP, scale Factor gồm 2,4,6 và Disp là hằng 8bit, 16bit hoặc 32bit.
Bài tập làm quen
1
2
3
4
5
6
7
8
mov rax,[Val] | RIP + DISP
mov rax,[rbx] | baseReg
mov rax,[rbx+16] | baseReg + Disp
mov rax,[r15*8+48] | indexReg * scaleFactor + Disp
mov rax,[rbx+r15] | baseReg + indexReg
mov rax,[rbx+r15+32] | baseReg + indexReg + Disp
mov rax,[rbx+r15*8] | baseReg + indexReg * scaleFactor
mov rax,[rbx+r15*8+64] | baseReg + indexReg * scaleFactor + Disp
Các tập lệnh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
adc Add with carry – Cộng hai số + cờ Carry (CF). Dùng khi thực hiện phép cộng nhiều phần (như cộng 64-bit bằng 2 lần 32-bit).
add Cộng hai số nguyên. Cập nhật các cờ như CF (carry), ZF (zero), OF (overflow).
dec Giảm giá trị xuống 1.
inc Tăng giá trị lên 1.
mul Nhân số nguyên không dấu. Nhân ngầm với thanh ghi AL, AX, EAX hoặc RAX.
imul Nhân số nguyên có dấu. Có thể dùng 2 hoặc 3 toán hạng.
div Chia không dấu. Thường chia AX, DX:AX, EDX:EAX, hoặc RDX:RAX.
idiv Chia có dấu. Cách dùng như div.
neg Đảo dấu (âm thành dương, dương thành âm): neg eax = 0 - eax.
and Phép AND từng bit giữa 2 toán hạng. Thường dùng để làm sạch bit (mask).
or Phép OR từng bit. Dùng để bật bit cụ thể.
not Phủ định bit: đảo từng bit (1 → 0, 0 → 1).
bsf Bit Scan Forward – tìm bit 1 đầu tiên từ LSB (ít ý nghĩa nhất).
bsr Bit Scan Reverse – tìm bit 1 đầu tiên từ MSB (nhiều ý nghĩa nhất).
bt Bit Test – kiểm tra bit tại vị trí cụ thể, lưu kết quả vào cờ CF.
btr Bit Test and Reset – như bt nhưng đặt bit đó về 0.
bts Bit Test and Set – như bt nhưng đặt bit đó thành 1.
lahf Tải các cờ trạng thái (SF, ZF, AF, PF, CF) từ RFLAGS vào thanh ghi AH.
cld Xóa cờ Direction Flag (DF) → đảm bảo các lệnh chuỗi (string ops) tăng địa chỉ thay vì giảm.
mov Di chuyển dữ liệu từ nguồn đến đích.
movsx / movsxd Di chuyển số nguyên có kéo dấu (sign extension).
movzx Di chuyển số nguyên có thêm 0 vào phần trên (zero extension).
lea Load Effective Address – Tính địa chỉ hiệu dụng, nhưng không truy cập bộ nhớ. Rất hữu dụng để tính toán nhanh.
cmp So sánh 2 toán hạng (như phép trừ, không lưu kết quả mà chỉ cập nhật cờ).
cmovcc Conditional Move – Di chuyển nếu thỏa điều kiện, ví dụ cmove (equal), cmovg (greater)...
jcc Jump nếu có điều kiện, như je, jne, jl, jg, ja, jb...
jmp Jump không điều kiện – nhảy thẳng đến nhãn hoặc địa chỉ.
call Gọi thủ tục: đẩy địa chỉ tiếp theo vào stack rồi nhảy đến hàm.
ret (không có trong danh sách nhưng liên quan) – trở về từ call.
cmpsb, cmpsw, cmpsd, cmpsq So sánh 2 chuỗi byte/word/dword/qword – tự động tăng/giảm địa chỉ dựa trên DF.
lodsb, lodsw, lodsd, lodsq Nạp một phần tử chuỗi từ [rsi] vào al/ax/eax/rax.
cpuid Truy vấn thông tin CPU: vendor, features, số core...
cwd, cdq, cqo Mở rộng dấu trước khi chia (dành cho idiv), ví dụ: cdq chuyển EAX → EDX:EAX có dấu.
Bài tập cộng trừ số với assembly và c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// main.cpp
#include "stdio.h"
#define ASSEMBLY
#ifdef ASSEMBLY
extern "C" int Sum_(int a, int b, int c);
extern "C" int Sub_(int a, int b);
#else
int Sum_(int a, int b, int c)
{
return a + b + c;
}
int Sub_(int a, int b)
{
return a - b;
}
#endif
void printOutput(int result)
{
printf("%d\n",result);
}
int main()
{
int a, b, c, sum, sub;
a = 2;
b = 20;
c = 20;
sum = Sum_(a, b, c);
sub = Sub_(a, b);
printOutput(sum);
printOutput(sub);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// kon.asm
.CODE
Sum_ PROC
MOV RAX, RCX
ADD RAX, RDX
ADD RAX, R8
ret
Sum_ ENDP
Sub_ Proc
MOV RAX, RCX
SUB RAX, RDX
RET
Sub_ ENDP
END
Toán tử LOGIC
Với toán tử logic ta sẽ làm quen với các phép toán XOR, AND, OR và một chút shift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// main.cpp
#include "stdio.h"
#define ASSEMBLY
#ifdef ASSEMBLY
extern "C" int Sum_(int a, int b, int c);
extern "C" int Sub_(int a, int b);
extern "C" int Xor_(int a, int b);
extern "C" int And_(int a, int b);
#else
#endif
void printOutput(int result)
{
printf("the dick make the eye binds %d\n",result);
}
int main()
{
int a, b, c, sum, sub, xor_, and_;
a = 2;
b = 20;
c = 20;
sum = Sum_(a, b, c);
sub = Sub_(a, b);
xor_ = Xor_(a, b);
and_ = And_(a, b);
printOutput(sum);
printOutput(sub);
printOutput(xor_);
printOutput(and_);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
kon.asm
.CODE
Sum_ PROC
MOV RAX, RCX
ADD RAX, RDX
ADD RAX, R8
ret
Sum_ ENDP
Sub_ Proc
MOV RAX, RCX
SUB RAX, RDX
RET
Sub_ ENDP
Xor_ Proc
MOV RAX, RCX
XOR RAX, RDX
RET
Xor_ ENDP
And_ Proc
MOV RAX, RCX
AND RAX, RDX
RET
And_ ENDP
END
This post is licensed under CC BY 4.0 by the author.