如何将 DLL 注入 Adob​​e Reader X

Posted

技术标签:

【中文标题】如何将 DLL 注入 Adob​​e Reader X【英文标题】:How to inject a DLL into Adobe Reader X 【发布时间】:2011-06-10 11:29:32 【问题描述】:

我需要将一个 DLL 注入到 Adob​​e Reader X 中,以读取发送到滚动条的事件(即使它是隐藏的)。我需要这样做才能找出我在文档的哪一页。

我尝试使用 win32 挂钩 API 挂钩 dll,我为桌面上的所有进程提供 CBT 挂钩并监听 Adob​​e Reader X 窗口的创建,然后用我的滚动条挂钩挂钩此窗口。

问题是我从来没有在 Adob​​e Reader X 上放置滚动条挂钩,在创建这些窗口时,我没有收到这些窗口的创建窗口或窗口激活消息。我如何获取这些消息以及如何连接到 Adob​​e Reader X?

#define WIN32_LEAN_AND_MEAN  
#include <windows.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "pdfviewlib.h"
#include <sstream>

#pragma data_seg(".PDFVIEWLIB")
PDFVIEWOBJ pdfviewobj[MAX_PDFOBJS] = NULL;
HHOOK globalhook = NULL;
BOOL debug = TRUE;
INT sSlide = 0;

#pragma data_seg()
#pragma comment(linker, "/SECTION:.PDFVIEWLIB,RWS")

#define DEBUG(...)  if(debug) printf(__VA_ARGS__)

HINSTANCE hInstance = NULL;

static int tAttach = 0;
static int tDetach = 0;

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )

    hInstance = (HINSTANCE)hModule;
    switch (ul_reason_for_call)
    
    case DLL_PROCESS_ATTACH:
        DEBUG("PROCESS_ATTACH\n");
        break;
    case DLL_THREAD_ATTACH:
        DEBUG("THREAD_ATTACH %i\n",tAttach++);
        break;
    case DLL_THREAD_DETACH:
        DEBUG("THREAD_DETACH %i\n", tDetach++);
        break;
    case DLL_PROCESS_DETACH:
        // Clean up... hopefully there is only the one process attached? 
        DEBUG("PROCESS_DETACH\n");
        for(int i = 0; i<MAX_PDFOBJS; i++)
            ClosePDF(i);
        break;
    
    return TRUE;

DllExport void SetDebug(BOOL onoff)

    printf("SetDebug\n");
    debug = onoff;
    DEBUG("enabled\n");



//Check if Acrobat Reader is installed
DllExport BOOL CheckInstalled()

    DEBUG("CheckInstalled\n");
    char cmdline[MAX_PATH * 2];
    return GetPDFViewerPath(cmdline, sizeof(cmdline));


// Open the PDF
DllExport int OpenPDF(char *filename, HWND hParentWnd, int startSlide)

    STARTUPINFO * si = (STARTUPINFO *) malloc(sizeof(STARTUPINFO));
    PROCESS_INFORMATION * pi = (PROCESS_INFORMATION*) malloc(sizeof(PROCESS_INFORMATION));
    char cmdline[MAX_PATH * 2];
    int id;
    sSlide = startSlide;


    DEBUG("OpenPDF start: %u", hParentWnd);
    //First check if Acrobat Reader is installed before continuing
    if(GetPDFViewerPath(cmdline, sizeof(cmdline))==FALSE)
    
        DEBUG("OpenPDF: GetPDFTViewerPath failed\n");
        return -1;
    
    id = -1;
    for(int i = 0; i<MAX_PDFOBJS; i++)
    
        if(pdfviewobj[i].state==PDF_CLOSED)
        
            id=i;
            break;
        
    
    if(id<0)
    
        DEBUG("OpenPDF: Too many PDFs\n");
        return -1;
    
    if (pdfviewobj[id].state == PDF_STARTED) 
    
        DEBUG("RERUN WHEN PDF_STARTED\n");
        return -1;
    
    memset(&pdfviewobj[id], 0, sizeof(PDFVIEWOBJ));
    strcpy_s(pdfviewobj[id].filename, MAX_PATH, filename);

    pdfviewobj[id].state = PDF_CLOSED;
    pdfviewobj[id].currentSlide = 0;
    pdfviewobj[id].hParentWnd = hParentWnd;
    pdfviewobj[id].hWnd = NULL;
    pdfviewobj[id].hWnd2 = NULL;

    strcat_s(cmdline, MAX_PATH * 2, "\\AcroRd32.exe /n /s /o");
    strcat_s(cmdline, MAX_PATH * 2, " \"");
    strcat_s(cmdline, MAX_PATH * 2, filename);
    strcat_s(cmdline, MAX_PATH * 2, "\"");
    si = (STARTUPINFO *)memset(si, 0, sizeof(STARTUPINFO));
    pi = (PROCESS_INFORMATION *)memset(pi, 0, sizeof(PROCESS_INFORMATION)); 
    if(globalhook!=NULL)
        UnhookWindowsHookEx(globalhook);
        DEBUG("Global unhooked\n");
        globalhook = NULL;
    
    //Set the global hook listening for Window Create/Window Activate messages
    globalhook = SetWindowsHookEx(WH_CBT,CbtProc,hInstance,NULL);
    if(globalhook==NULL)
    
        DEBUG("OpenPDF: Global SetWindowsHookEx failed\n");
        DEBUG("ERROR: %X\n", GetLastError());
        globalhook = NULL;
        ClosePDF(id);
        return -1;
    
    else DEBUG("GLOBAL HOOKED %X\n", globalhook);
    pdfviewobj[id].state = PDF_STARTED;
    Sleep(10); 
    DEBUG(cmdline);
    //Run Acrobat Reader, PDF STATE SET TO STARTED
    if(!CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, 0, NULL, si, pi))
    
        DEBUG("OpenPDF: CreateProcess failed\n");
        ClosePDF(id);
        return -1;
    
    pdfviewobj[id].dwProcessId = pi->dwProcessId;
    pdfviewobj[id].dwThreadId = pi->dwThreadId;
    pdfviewobj[id].hThread = pi->hThread;
    pdfviewobj[id].hProcess = pi->hProcess;
    //WAIT FOR GLOBAL HOOK TO DETECT Acrobat Windows and set PDF STATE TO PDF_OPENED
    //For some reason the loops exits and PDFSTATE is PDF_CLOSED...  
    while(pdfviewobj[id].state==PDF_STARTED)
        Sleep(50);
    DEBUG("PDFSTATE == CLOSED = %i \n", pdfviewobj[id].state==PDF_CLOSED);
    DEBUG("PDFSTATE == STARTED = %i \n", pdfviewobj[id].state==PDF_STARTED);
    DEBUG("PDFSTATE == OPENED = %i \n", pdfviewobj[id].state==PDF_OPENED);
    DEBUG("PDFSTATE == LOADED = %i \n", pdfviewobj[id].state==PDF_LOADED);
    if (sSlide > 0)
        GotoSlide(id, sSlide+1);
    
    pdfviewobj[id].state = PDF_LOADED;
    DEBUG("OpenPDF Done: id=%i\n", id);
    return id;


// Get the path of Acrobat Reader X from the registry 
BOOL GetPDFViewerPath(char *pdfviewerpath, int strsize)

    HKEY hkey;
    DWORD dwtype, dwsize;
    LRESULT lresult;

    DEBUG("GetPDFViewerPath: start\n");
        if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Adobe\\Acrobat Reader\\9.0\\InstallPath", 0, KEY_READ, &hkey)!=ERROR_SUCCESS)            
            return FALSE;   
    dwtype = REG_SZ;
    dwsize = (DWORD)strsize;
    lresult = RegQueryValueEx(hkey, NULL, NULL, &dwtype, (LPBYTE)pdfviewerpath, &dwsize );
    RegCloseKey(hkey);
    if(lresult!=ERROR_SUCCESS)
        return FALSE;
    DEBUG("GetPDFViewerPath: exit ok \n");
    return TRUE;


// Unhook the Windows hook 
void Unhook(int id)

    DEBUG("Unhook: start %i\n", id);
    if(pdfviewobj[id].hook!=NULL)   
        UnhookWindowsHookEx(pdfviewobj[id].hook);
    pdfviewobj[id].hook = NULL;
    DEBUG("Unhook: exit ok\n");


// Close the Acrobat Reader, release resources
DllExport void ClosePDF(int id)

    DEBUG("ClosePDF: start %i\n", id);
    if (globalhook != NULL) 
        DEBUG("GLOBAL UNHOOKED %X\n", globalhook);
        UnhookWindowsHookEx(globalhook);
        globalhook = NULL;

    
    else DEBUG("GLOBAL NOT UNHOOKED\n");
    pdfviewobj[id].state = PDF_CLOSED;
    Unhook(id);
    if(pdfviewobj[id].hWnd==0)
        TerminateThread(pdfviewobj[id].hThread, 0);
    else
        PostMessage(pdfviewobj[id].hWnd, WM_CLOSE, 0, 0);
    CloseHandle(pdfviewobj[id].hThread);
    CloseHandle(pdfviewobj[id].hProcess);
    memset(&pdfviewobj[id], 0, sizeof(PDFVIEWOBJ)); 
    DEBUG("ClosePDF: exit ok\n");
    return;

// Return the number of the slide currently viewing
DllExport int GetCurrentSlide(int id)

    DEBUG("GetCurrentSlide:%d\n", id);
    if(pdfviewobj[id].state==0)
        return -1;
    else
        return pdfviewobj[id].currentSlide;


// Take a step forwards through the show 
DllExport void NextStep(int id)

    DEBUG("NextStep:%d\n", id);
    SetForegroundWindow(pdfviewobj[id].hWnd);
    SetFocus(pdfviewobj[id].hWnd);
    PostMessage(pdfviewobj[id].hWnd2, WM_MOUSEWHEEL, MAKEWPARAM(0, -WHEEL_DELTA), 0);


// Take a step backwards through the show 
DllExport void PrevStep(int id)

    DEBUG("PrevStep:%d\n", id);
    SetForegroundWindow(pdfviewobj[id].hWnd);
    SetFocus(pdfviewobj[id].hWnd);
    PostMessage(pdfviewobj[id].hWnd2, WM_MOUSEWHEEL, MAKEWPARAM(0, WHEEL_DELTA), 0);


// Go directly to a slide
DllExport void GotoSlide(int id, int slideno)
   
    //TODO: USE SETSCROLLINFO 



// This hook is started with the AcroRd32.EXE process and waits for the WM_CREATEWND message. 
// Release the hook as soon as we're complete to free up resources
LRESULT CALLBACK CbtProc(int nCode, WPARAM wParam, LPARAM lParam)

    HHOOK hook = globalhook;
    DEBUG("HOOK: %X\n", hook);
    if (nCode < 0) 
        return CallNextHookEx(hook, nCode, wParam, lParam);
    
    else if(nCode==HCBT_CREATEWND)
    
        DEBUG("CREATE WINDOW \n");
        char csClassName[16];
        char csCaptionName[16];
        HWND hCurrWnd = (HWND)wParam;
        DWORD retProcId = NULL;
        GetClassName(hCurrWnd, csClassName, sizeof(csClassName));
        GetWindowText(hCurrWnd, csCaptionName, sizeof(csCaptionName));
        if((strcmp(csClassName, "AcrobatSDIWindow")==0)
          ||(strcmp(csClassName, "AVL_AVView")==0))
        
            DEBUG("%s found \n", csClassName);
            int id=-1;
            DWORD windowthread = GetWindowThreadProcessId(hCurrWnd,NULL);
            for(int i=0; i<MAX_PDFOBJS; i++)
            
                if(pdfviewobj[i].dwThreadId==windowthread)
                
                    id=i;
                    break;
                
            
            if(id>=0)
            
                DEBUG("Matched threadid!\n");
                if(strcmp(csClassName, "AVL_AVView")==0)
                    if (strcmp(csCaptionName, "AVPageView")==0)
                        pdfviewobj[id].hWnd2=hCurrWnd;
                    
                
                else        
                
                    pdfviewobj[id].hWnd=hCurrWnd;
                    CBT_CREATEWND* cw = (CBT_CREATEWND*)lParam;
                    if(pdfviewobj[id].hParentWnd!=NULL) 
                        cw->lpcs->hwndParent = pdfviewobj[id].hParentWnd;
                
                if((pdfviewobj[id].hWnd!=NULL)&&(pdfviewobj[id].hWnd2!=NULL))
                
                    pdfviewobj[id].hook = SetWindowsHookEx(WH_CALLWNDPROC,CwpProc,hInstance,pdfviewobj[id].dwThreadId);
                    if (pdfviewobj[id].hook != NULL) 
                        DEBUG("Global UNHOOKED %X\n", globalhook);
                        UnhookWindowsHookEx(globalhook);
                        globalhook=NULL;                        
                        pdfviewobj[id].state = PDF_OPENED;
                                       
                    Sleep(10);                  
                
            
        
    
    return CallNextHookEx(hook,nCode,wParam,lParam); 



LRESULT CALLBACK CwpProc(int nCode, WPARAM wParam, LPARAM lParam)
    CWPSTRUCT *cwp;
    cwp = (CWPSTRUCT *)lParam;
    HHOOK hook = NULL;

    DWORD windowthread = GetWindowThreadProcessId(cwp->hwnd,NULL);
    int id=-1;
    for(int i=0; i<MAX_PDFOBJS; i++)
    
        if(pdfviewobj[i].dwThreadId==windowthread)
        
            id=i;
            hook = pdfviewobj[id].hook;
            break;
        
    
    if((id>=0)&&(nCode==HC_ACTION))
    
        DEBUG("CBT HC_ACTION\n");
        if(cwp->message==SBM_SETSCROLLINFO)
        
            DEBUG("CBT SBM_SETSCROLLINFO\n");
            SCROLLINFO *scrInf;
            scrInf = (SCROLLINFO *)cwp->lParam;
            pdfviewobj[id].currentSlide = scrInf->nPos;             
        
        if((pdfviewobj[id].state != PDF_CLOSED)&&(cwp->message==WM_CLOSE||cwp->message==WM_QUIT))
            pdfviewobj[id].state = PDF_CLOSING;
        
    
    return CallNextHookEx(hook,nCode,wParam,lParam); 

如果你需要,这里是标题

#define DllExport extern "C"  __declspec( dllexport ) 

enum PDFVIEWSTATE  PDF_CLOSED, PDF_STARTED, PDF_OPENED, PDF_LOADED, PDF_CLOSING;

DllExport int OpenPDF(char *filename, HWND hParentWnd, int startSlide);
DllExport BOOL CheckInstalled();
DllExport void ClosePDF(int id);
DllExport int GetCurrentSlide(int id);
DllExport void NextStep(int id);
DllExport void PrevStep(int id);
DllExport void GotoSlide(int id, int slideno);

DllExport void SetDebug(BOOL onoff);

LRESULT CALLBACK CbtProc(int nCode, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK CwpProc(int nCode, WPARAM wParam, LPARAM lParam);
BOOL GetPDFViewerPath(char *pdfviewerpath, int strsize);

void Unhook(int id);

//MAXUMUM NUMBER OF PDF-PROCESSES CURRENTLY SET TO ONE
#define MAX_PDFOBJS 1

struct PDFVIEWOBJ 

    HHOOK hook;
    HWND hWnd;
    HWND hWnd2;
    HWND hParentWnd;
    HANDLE hProcess;
    HANDLE hThread;
    DWORD dwProcessId;
    DWORD dwThreadId;
    int currentSlide;
    char filename[MAX_PATH];
    PDFVIEWSTATE state;
;

【问题讨论】:

我想知道 eula 是否允许这样做;) 如果不查看您编写的代码,就无法帮助您。 SetWindowsHookEx() 应该是一个相当简单的过程,所以我相信一旦你上传了你的代码,人们就能很快地提供帮助。 我是否正确地说你是先手动注入你的 DLL 和别的东西?你不应该那样做。如果您正确使用 SetWindowsHookEx(),它会为您执行注入。此外,如果您的 DLL 已经在其中,那么我相信您应该为 hMod 传递 NULL 不,我正在加载库,然后使用 dllextern openPDF 放置全局钩子并打开 adobe reader(从注册表读取它所在的位置)。然后线程处于休眠状态,直到线程的状态!= 开始...只需查看 openpdf 【参考方案1】:

Adobe Reader 通常在保护模式下运行。 (请参阅编辑/首选项/安全(增强)。取消选中“启动时启用保护模式”复选框。

重新启动阅读器,看看您是否收到消息。你应该。问题是用户界面特权隔离 (UIPI) 不允许许多 Windows 消息跨越以不同完整性级别(低/中/高)运行的进程之间的进程边界。您应该能够通过 ChangeWindowMessageFilterEx() 更改 windows 消息过滤器。

我目前在使用 Adob​​e Reader Xi 时遇到问题,其中 ChangeWindowsMessageFilter 和 ChangeWindowMessageFilterEx 似乎没有改变 Adob​​e 阅读器在挂钩过程中向全局挂钩接收器发送消息的行为。我已将 noteapad.exe 复制到 notepad2.exe 并通过以下方式将其完整性级别降低到低:icacls notepad2.exe /setintegritylevel low (从提升的 cmd 提示符运行(即以管理员身份运行))。当我这样做时,我的挂钩工作正常(使用 ChangeWindowMessageFilterEx()),但仍然没有收到来自 Adob​​e 的挂钩消息。

此外,Reader 是 32 位的,因此请确保您从 32 位挂钩进程中挂钩它,否则您也不会看到消息)。

【讨论】:

adobe 阻塞挂钩可能还有其他问题。请参阅此问答:forum.madshi.net/viewtopic.php?f=7&t=27832 基本上,Adobe 在其渲染过程中挂钩操作系统并在加载之前卸载注入的 DLL。

以上是关于如何将 DLL 注入 Adob​​e Reader X的主要内容,如果未能解决你的问题,请参考以下文章

如何在保存 PDF 表单时阻止 Adob​​e Reader 询问“另存为”(即只允许“保存”)?

如何永久更改 Adob​​e Acrobat Reader DC 中的荧光笔颜色?

从 Adob​​e Reader 的 ActiveX 控件获取 PDF 文档的页码

使用 VBA 和 Adob​​e PDF Reader 控件复制选定的文本

另存为 PDF 并在 Adob​​e Reader 中作为新标签打开

通过 c# 中的进程保存在 Adob​​e Reader 中打开的 pdf 文件