如何将 DLL 注入 Adobe Reader X
Posted
技术标签:
【中文标题】如何将 DLL 注入 Adobe Reader X【英文标题】:How to inject a DLL into Adobe Reader X 【发布时间】:2011-06-10 11:29:32 【问题描述】:我需要将一个 DLL 注入到 Adobe Reader X 中,以读取发送到滚动条的事件(即使它是隐藏的)。我需要这样做才能找出我在文档的哪一页。
我尝试使用 win32 挂钩 API 挂钩 dll,我为桌面上的所有进程提供 CBT 挂钩并监听 Adobe Reader X 窗口的创建,然后用我的滚动条挂钩挂钩此窗口。
问题是我从来没有在 Adobe Reader X 上放置滚动条挂钩,在创建这些窗口时,我没有收到这些窗口的创建窗口或窗口激活消息。我如何获取这些消息以及如何连接到 Adobe 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 消息过滤器。
我目前在使用 Adobe Reader Xi 时遇到问题,其中 ChangeWindowsMessageFilter 和 ChangeWindowMessageFilterEx 似乎没有改变 Adobe 阅读器在挂钩过程中向全局挂钩接收器发送消息的行为。我已将 noteapad.exe 复制到 notepad2.exe 并通过以下方式将其完整性级别降低到低:icacls notepad2.exe /setintegritylevel low (从提升的 cmd 提示符运行(即以管理员身份运行))。当我这样做时,我的挂钩工作正常(使用 ChangeWindowMessageFilterEx()),但仍然没有收到来自 Adobe 的挂钩消息。
此外,Reader 是 32 位的,因此请确保您从 32 位挂钩进程中挂钩它,否则您也不会看到消息)。
【讨论】:
adobe 阻塞挂钩可能还有其他问题。请参阅此问答:forum.madshi.net/viewtopic.php?f=7&t=27832 基本上,Adobe 在其渲染过程中挂钩操作系统并在加载之前卸载注入的 DLL。以上是关于如何将 DLL 注入 Adobe Reader X的主要内容,如果未能解决你的问题,请参考以下文章
如何在保存 PDF 表单时阻止 Adobe Reader 询问“另存为”(即只允许“保存”)?
如何永久更改 Adobe Acrobat Reader DC 中的荧光笔颜色?
从 Adobe Reader 的 ActiveX 控件获取 PDF 文档的页码
使用 VBA 和 Adobe PDF Reader 控件复制选定的文本