文号
t33405
阅读
10603
回复
9
收藏
7
写了个简单的线程注入的例子,可以做些小坏事!~
2011/05/03
IP:湖北
一个简单的WIN32程序;
平台VC++ 6.0
干掉360老的版本是可以的


//线程参数结构体定义
typedef struct _RemoteParam
{
    char szMsg[12];    //MessageBox函数中显示的字符提示
    DWORD dwMessageBox;//MessageBox函数的入口地址
} RemoteParam, * PRemoteParam;

//定义MessageBox类型的函数指针
typedef int (__stdcall * PFN_MESSAGEBOX)(HWND, LPCTSTR, LPCTSTR, DWORD);

//线程函数定义
DWORD __stdcall threadProc(LPVOID lParam)
{
    RemoteParam* pRP = (RemoteParam*)lParam;

    PFN_MESSAGEBOX pfnMessageBox;
    pfnMessageBox = (PFN_MESSAGEBOX)pRP->dwMessageBox;
    pfnMessageBox(NULL, pRP->szMsg, pRP->szMsg, 0);

    return 0;
}

//提升进程访问权限
bool enableDebugPriv()
{
    HANDLE hToken;
    LUID sedebugnameValue;
    TOKEN_PRIVILEGES tkp;
  
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
    {
        return false;
    }

    if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue))
    {
        CloseHandle(hToken);
        return false;
    }

    tkp.PrivilegeCount = 1;
    tkp.Privileges[0].Luid = sedebugnameValue;
    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL))
    {
        CloseHandle(hToken);
        return false;
    }

    return true;
}

//根据进程名称得到进程ID,如果有多个运行实例的话,返回第一个枚举到的进程的ID
DWORD processNameToId(LPCTSTR lpszProcessName)
{
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 pe;
    pe.dwSize = sizeof(PROCESSENTRY32);

    if (!Process32First(hSnapshot, &pe))
    {
        
        return 0;
    }

    while (Process32Next(hSnapshot, &pe))
    {
        if (!StrCmpI(lpszProcessName, pe.szExeFile))
        {
            return pe.th32ProcessID;
        }
    }

    return 0;
}

int main(int argc, char* argv[])
{
    //定义线程体的大小
    const DWORD dwThreadSize = 4096;
    DWORD dwWriteBytes;
    //提升进程访问权限
    enableDebugPriv();

    //等待输入进程名称,注意大小写匹配
    std::cout << "[s:9]lease input the name of target process !" << std::endl;
    char szExeName[MAX_PATH] = { 0 };
    std::cin >> szExeName;

    DWORD dwProcessId = processNameToId(szExeName);

    if (dwProcessId == 0)
    {
        MessageBox(NULL, "The target process have not been found !", "Notice", MB_ICONINFORMATION | MB_OK);
        return -1;
    }

    //根据进程ID得到进程句柄
    HANDLE hTargetProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);

    if (!hTargetProcess)
    {
        MessageBox(NULL, "Open target process failed !", "Notice", MB_ICONINFORMATION | MB_OK);
        return 0;
    }

    //在宿主进程中为线程体开辟一块存储区域
    //在这里需要注意MEM_COMMIT | MEM_RESERVE内存非配类型以及PAGE_EXECUTE_READWRITE内存保护类型
    //其具体含义请参考MSDN中关于VirtualAllocEx函数的说明。
    void* pRemoteThread = VirtualAllocEx(hTargetProcess, 0, dwThreadSize, MEM_COMMIT | MEM_RESERVE, \
        PAGE_EXECUTE_READWRITE);

    if (!pRemoteThread)
    {
        MessageBox(NULL, "Alloc memory in target process failed !", "notice", MB_ICONINFORMATION | MB_OK);
        return 0;
    }

    //将线程体拷贝到宿主进程中
    if (!WriteProcessMemory(hTargetProcess, pRemoteThread, &threadProc, dwThreadSize, 0))
    {
        MessageBox(NULL, "Write data to target process failed !", "Notice", MB_ICONINFORMATION | MB_OK);
        return 0;
    }
    //定义线程参数结构体变量
    RemoteParam remoteData;
    ZeroMemory(&remoteData, sizeof(RemoteParam));

    //填充结构体变量中的成员
    HINSTANCE hUser32 = LoadLibrary("User32.dll");
    remoteData.dwMessageBox = (DWORD)GetProcAddress(hUser32, "MessageBoxA");
    strcat(remoteData.szMsg, "Hello\0");

    //为线程参数在宿主进程中开辟存储区域
    RemoteParam* pRemoteParam = (RemoteParam *)VirtualAllocEx(hTargetProcess , 0, sizeof(RemoteParam), \
        MEM_COMMIT, PAGE_READWRITE);

    if (!pRemoteParam)
    {
        MessageBox(NULL, "Alloc memory failed !", "Notice", MB_ICONINFORMATION | MB_OK);
        return 0;
    }

    //将线程参数拷贝到宿主进程地址空间中
    if (!WriteProcessMemory(hTargetProcess, pRemoteParam, &remoteData, sizeof(remoteData), 0))
    {
        MessageBox(NULL, "Write data to target process failed !", "Notice", MB_ICONINFORMATION | MB_OK);
        return 0;
    }

    //在宿主进程中创建线程
    HANDLE hRemoteThread = CreateRemoteThread(hTargetProcess, NULL, 0, \
        (DWORD (__stdcall *)(void *))pRemoteThread, pRemoteParam, 0, &dwWriteBytes);

    if (!hRemoteThread)
    {
        MessageBox(NULL, "Create remote thread failed !", "Notice",  MB_ICONINFORMATION | MB_OK);
        return 0;
    }

    if (hRemoteThread)
    {
        ::WaitForSingleObject(hRemoteThread, INFINITE);
        ::CloseHandle(hRemoteThread);
    }
    
    ::VirtualFreeEx(hTargetProcess, pRemoteThread,    dwThreadSize, MEM_RELEASE);
    ::VirtualFreeEx(hTargetProcess, pRemoteParam,    sizeof(remoteData), MEM_RELEASE);
    ::CloseHandle(hTargetProcess);
    
    return 0;
}
attachment icon CreateRemoteThread.rar 9.01KB RAR 24次下载
+500
科创币
我说要有光
2011/05/03
有价值的原创内容
15年8个月前IP:未同步
292575
1楼
直接给程序签名就可以轻松解决了
引用
评论
15年8个月前IP:未同步
292594
2楼
很长时间不写程序了,so [s:255]
引用
评论
15年8个月前IP:未同步
292621
3楼
赞扬下``` 若是能配上以嵌入汇编调用被注入软件的CALL的教程就更好了
引用
评论
15年8个月前IP:未同步
292629
4楼
很长时间不写程序了,so [s:255]
引用
评论
joyeep作者
15年8个月前IP:未同步
294294
5楼
回 3楼(我说要有光) 的帖子
有这个想法,这个程序出生其实是个副产物,因为给别人做个挂,顺便写了个测试程序,等段时间想把线程注入弄得更完善;
引用
评论
15年8个月前IP:未同步
294306
6楼
这个代码在Win7下需要过UAC吧
引用
评论
15年8个月前IP:未同步
294836
7楼
回 6楼(小俊) 的帖子
外挂程序通常是在启动的时候请求管理员特权的,UAC会弹出是否允许
引用
评论
15年2个月前IP:未同步
332708
8楼
学习了     也模仿着做做
引用
评论
笔记
{{note.content}}
{{n.user.username}}
{{fromNow(n.toc)}} {{n.status === noteStatus.disabled ? "已屏蔽" : ""}} {{n.status === noteStatus.unknown ? "正在审核" : ""}} {{n.status === noteStatus.deleted ? '已删除' : ''}}
  • 编辑
  • 删除
  • {{n.status === 'disabled' ? "解除屏蔽" : "屏蔽" }}
我也是有底线的