【问题标题】:Windows privileges, getting handle of .dll when not admin, not sureWindows 权限,在非管理员时获取 .dll 的句柄,不确定
【发布时间】:2014-04-22 05:46:13
【问题描述】:

好的,我正在学习 Windows API 以及如何创建线程/进程和获得调试权限等。非常新,如果这是一个愚蠢的问题,我深表歉意。

无论如何,我正在创建一个 .dll 注入器来使用,并且通过注入我的 .dll 文件成功地注入了 32 位和 64 位进程,包括 explorer.exe。但是,我正在尝试在标准用户模式下对此进行测试,但在弄清楚如何操作时遇到了问题。

现在我正在为 .dll 和 injector.exe 编译为 x64。我正在尝试注入 x64 进程,主要是 explorer.exe(在管理员上工作)。使用 Visual Studio 2012,进行了一些优化,没有清单,没有调试(仅在需要时)。 操作系统= Win 7 x64

另外,我尝试从多个位置访问 .dll,E:\ 驱动器只是我 HD 上的另一个分区。

  1. 究竟为什么会发生这种情况?
  2. 有什么方法可以绕过它? (如有可能,请提供参考、解释、示例)

NtCreateThreadEx();调用返回一个为 0 的线程。因此它没有正确加载。

#include <windows.h>
#include <iostream>
#include <stdlib.h>
#include <tlhelp32.h>

#define CREATE_THREAD_ACCESS (PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ) 

using namespace std;

DWORD getPid(string procName);
int privileges();

typedef struct _UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;

typedef struct _OBJECT_ATTRIBUTES {
    ULONG Length;
    HANDLE RootDirectory;
    PUNICODE_STRING ObjectName;
    ULONG Attributes;
    PVOID SecurityDescriptor;
    PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES;
typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;

typedef DWORD(WINAPI *NTCREATETHREADEX)
(
PHANDLE ThreadHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
HANDLE ProcessHandle,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
BOOL CreateSuspended,
DWORD dwStackSize,
DWORD dw1,
DWORD dw2,
LPVOID Unknown
);

int main()
{
    cout << sizeof(void*) << endl;
    privileges();  //don't mind of the result, because maybe it fails because you already have that privilege

    DWORD pid = getPid("explorer.exe");
    if (pid == 0) return 1; //error

    HANDLE p;
    p = OpenProcess(CREATE_THREAD_ACCESS, false, pid);
    if (p == NULL) return 1; //error

    char * dll = "E:\\logger_mailer.dll";
    BOOL is32 = FALSE;
    BOOL fnWow64Ret = IsWow64Process(p, &is32);

    if (!fnWow64Ret)
    {
        cout<<"Error!!!!!!"<<endl;
        return 1;
    }

    //if (is32)  //If true process is 32 bit
    //  dll = "D:\\logger_mailer.dll";
    //else
    //{
    //  dll = "D:\\logger_mailer.dll";
    //  //cout<<"Error"<<endl;
    //}

    unsigned long LoadLib = (unsigned long)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");

    LPVOID DataAddress = VirtualAllocEx(p, NULL, strlen(dll) + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

    WriteProcessMemory(p, DataAddress, dll, strlen(dll), NULL);

    HANDLE thread;
    NTCREATETHREADEX NtCreateThreadEx = (NTCREATETHREADEX)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtCreateThreadEx");
    if (NtCreateThreadEx) {
        NtCreateThreadEx(&thread, GENERIC_ALL, NULL, p, (LPTHREAD_START_ROUTINE)LoadLib, DataAddress, FALSE, NULL, NULL, NULL, NULL);
    }
    else {
        thread = CreateRemoteThread(p, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLib, DataAddress, NULL, NULL);
    }

    if (thread != 0){
        //injection completed
        WaitForSingleObject(thread, INFINITE);   //this waits untill thread thread has finished
        VirtualFree(dll, 0, MEM_RELEASE); //free myFunc memory
        VirtualFree(DataAddress, 0, MEM_RELEASE); //free data memory
        CloseHandle(thread);
        CloseHandle(p);  //don't wait for the thread to finish, just close the handle to the process
        cout << "Injection completed!" << endl;
    }
    else{
        cout << "Error!" << endl;
    }


    system("PAUSE");
    return EXIT_SUCCESS;
}

DWORD getPid(string procName){
    HANDLE hsnap;
    PROCESSENTRY32 pt;
    hsnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    pt.dwSize = sizeof(PROCESSENTRY32);
    do{
        if (!strcmp(pt.szExeFile, procName.c_str())){
            DWORD pid = pt.th32ProcessID;
            CloseHandle(hsnap);
            return pid;
        }
    } while (Process32Next(hsnap, &pt));
    CloseHandle(hsnap);
    return 0;
}

int privileges(){
    HANDLE Token;
    TOKEN_PRIVILEGES tp;
    if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &Token))
    {
        LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
        tp.PrivilegeCount = 1;
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
        if (AdjustTokenPrivileges(Token, 0, &tp, sizeof(tp), NULL, NULL) == 0){
            return 1; //FAIL
        }
        else{
            return 0; //SUCCESS
        }
    }
    return 1;
}

编辑:所以,在 David 和 Harry 基本上是哄骗我之后,我发现是我的 .dll 代码失败了。此外,我不需要使用 NtCreateThreadEx(),因为 CreateRemoteThread() 确实适用于 win 7 x64。 SO和其他网站上的许多帖子另有说明。显示一个简单的消息框进行验证。

奇怪的是 NtCreateThreadEx() 在管理员模式下工作,而不是在标准模式下。

【问题讨论】:

  • 听起来编译器已经优化了该代码。
  • 只是一个指针local var的赋值。编译器不需要 var。
  • 你的问题是什么?你想了解调试器的行为吗
  • 你读错了。如果你需要帮助,你应该问真正的问题,而不是给我们虚假的线索和不必要的 asm。
  • 要诊断实际问题,您需要做的主要事情是添加错误检查,以便您知道哪个 API 调用失败,以及错误代码是什么。有了这些信息,我们或许可以提供帮助。

标签: windows winapi dll privileges dll-injection


【解决方案1】:

我可以看到以下问题:

  1. 在对WriteProcessMemory 的调用中,您传递了错误的长度。您需要传递 strlen(...)+1 才能写入空终止符。
  2. 无需使用未记录的NtCreateThreadEx。使用CreateRemoteThread 非常适合注入。
  3. 您只检查了某些 API 调用的错误。您需要检查所有 API 调用的错误。如果你不这样做,没有人知道他们是否成功。

不管怎样,我从来不用AdjustTokenPrivileges 注入。我相信你可以跳过这一步。


在评论中,您声明您正在注入不同的会话。你会发现你需要NtCreateThreadEx 而不是CreateRemoteThread,而且这种注入只有在提升时才有效。当然,在不同会话中注入进程的要求非常重要。这应该包含在问题中,而不是出现在 cmets 中。

但是,您不应该对需要提升权限以注入不同会话中的进程感到惊讶。对于这种情况,很可能需要添加SE_DEBUG_NAME

简而言之,在我看来,系统告诉您运行提升权限以便在不同会话中注入进程。这似乎很合理。


另一方面,您还在 cmets 中声明 CreateRemoteThread 返回一个非零值。这表明成功。这似乎是说您误诊了问题。如果CreateRemoteThread 成功,那么远程线程将运行。接下来你需要找出在那之后失败的地方。

而且您还说您正在尝试注入不在会话 0 中运行的explorer 进程。所以这里有很多混乱。也许我在添加这个答案时跳了枪。

无论如何,为了让您继续,我建议:

  1. 修复对WriteProcessMemory的调用。
  2. 确定目标进程在哪个会话中。
  3. 添加错误检查。

【讨论】:

  • 你怎么知道DLL永远不会执行?
  • 使用进程资源管理器确认您的 DLL 正在加载。您必须了解,从我们的角度来看,我们必须怀疑您提供的所有信息!在我看来,远程线程开始了。接下来会发生什么,谁知道呢。这似乎不是问题的一部分。
  • 不知道。我不知道你的DLL在做什么。如果您知道我的意思,我并不是非常热衷于一直调试到最后。 DLL 是否加载到资源管理器进程中?
  • 在 Process explorer 的 View 菜单中启用“Show Lower Pane”。然后选择查看 |下窗格视图 | DLL。然后在树形视图中选择 explorer.exe。然后在下部窗格中查找您的 DLL。
  • ASLR 会不会咬你? kernel32 在资源管理器进程中的基地址是否可能与您的进程不同。换句话说,您传递的线程过程是无效的。
猜你喜欢
  • 2011-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-05
  • 1970-01-01
  • 1970-01-01
  • 2013-04-20
相关资源
最近更新 更多