找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 14048|回复: 30

[VB]调用vc Dll出错

[复制链接]

4

主题

31

回帖

155

积分

用户组: 小·技术宅

UID
7284
精华
0
威望
1 点
宅币
118 个
贡献
0 次
宅之契约
0 份
在线时间
10 小时
注册时间
2021-7-13
发表于 2021-7-14 11:20:19 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
模块代码:

  1. Public Declare Function HookApi Lib "D:\HookApi.dll" (ByVal hWnd As Long, ByVal ModuleName As String, ByVal FunctionName As String, ByVal FnctionAddr As Long) As Boolean

  2. Public Declare Sub UnHookApi Lib "D:\HookApi.dll" ()

  3. Public Declare Sub HookOn Lib "D:\HookApi.dll" ()

  4. Public Declare Sub HookOff Lib "D:\HookApi.dll" ()

  5. Public Declare Function MessageBox Lib "user32" Alias "MessageBoxA" (ByVal hWnd As Long, ByVal lpText As String, ByVal lpCaption As String, ByVal uType As Long) As Long

  6. Public Function My_MessageBox(ByVal hWnd As Long, ByVal lpText As String, ByVal lpCaption As String, ByVal uType As Long) As Long

  7. Debug.Print lpText & vbCrLf & lpCaption

  8. HookOff

  9. My_MessageBox = MessageBox(hWnd, lpText, lpCaption, uType)

  10. HookOn

  11. End Function
复制代码


窗体代码:

  1. Private Sub Command1_Click()

  2. MsgBox HookApi(Me.hWnd, "user32", "MessageBoxA", AddressOf My_MessageBox)

  3. End Sub

  4. Private Sub Command2_Click()

  5. UnHookApi

  6. End Sub

  7. Private Sub Command4_Click()

  8. MessageBox Me.hWnd, "Hi", "Hello", vbOK

  9. End Sub
复制代码


运行时总出现对话框Error:cannot get Function

求解释!
回复

使用道具 举报

4

主题

31

回帖

155

积分

用户组: 小·技术宅

UID
7284
精华
0
威望
1 点
宅币
118 个
贡献
0 次
宅之契约
0 份
在线时间
10 小时
注册时间
2021-7-13
 楼主| 发表于 2021-7-14 11:26:04 | 显示全部楼层
HookApi.dll代码:

HookApi.h:

  1. // HookApi.h : HookApi DLL 的主头文件
  2. //

  3. #pragma once

  4. #ifndef __AFXWIN_H__
  5.         #error "在包含此文件之前包含“stdafx.h”以生成 PCH 文件"
  6. #endif

  7. #include "resource.h"                // 主符号


  8. // CHookApiApp
  9. // 有关此类实现的信息,请参阅 HookApi.cpp
  10. //

  11. class CHookApiApp : public CWinApp
  12. {
  13. public:
  14.         CHookApiApp();

  15. // 重写
  16. public:
  17.         virtual BOOL InitInstance();

  18.         int ExitInstance();

  19.         DECLARE_MESSAGE_MAP()
  20. };
  21. #define  UM_WNDTITLE WM_USER+100 //自定义消息

  22. //全局共享变量
  23. #pragma data_seg(".Share")
  24. HWND g_hWnd = NULL;//主窗口句柄;
  25. HHOOK hhk = NULL;        //鼠标钩子句柄;
  26. HINSTANCE hInst = NULL;//本dll实例句柄;
  27. #pragma data_seg()
  28. #pragma comment(linker, "/section:.Share,rws")

  29. HANDLE hProcess = NULL;
  30. BOOL bIsInjected = FALSE;

  31. PTR oldFunc = NULL; //用于保存原函数地址
  32. FARPROC pfFunc = NULL;//指向原函数地址的远指针
  33. BYTE OldCodeA[5]; //老的系统API入口代码
  34. BYTE NewCodeA[5]; //要跳转的API代码 (jmp xxxx)
  35. PTR FunctionAddress;

  36. //安装钩子
  37. _declspec(dllexport) BOOL WINAPI _stdcall HookApi(HWND hWnd);
  38. //卸载钩子
  39. _declspec(dllexport) VOID WINAPI _stdcall UnHookApi();
复制代码


HookApi.cpp:

  1. // HookApi.cpp : 定义 DLL 的初始化例程。
  2. //

  3. #include "stdafx.h"
  4. #include "HookApi.h"

  5. #ifdef _DEBUG
  6. #define new DEBUG_NEW
  7. #endif

  8. // CHookApiApp

  9. BEGIN_MESSAGE_MAP(CHookApiApp, CWinApp)
  10. END_MESSAGE_MAP()


  11. // CHookApiApp 构造

  12. CHookApiApp::CHookApiApp()
  13. {
  14.         // TODO:  在此处添加构造代码,
  15.         // 将所有重要的初始化放置在 InitInstance 中
  16. }


  17. // 唯一的一个 CHookApiApp 对象

  18. CHookApiApp theApp;

  19. //开启钩子的函数
  20. void HookOn()
  21. {
  22.         ASSERT(hProcess != NULL);

  23.         DWORD dwTemp = 0, dwOldProtect, dwRet = 0, dwWrite;

  24.         VirtualProtectEx(hProcess, pfFunc, 5, PAGE_READWRITE, &dwOldProtect);
  25.         dwRet = WriteProcessMemory(hProcess, pfFunc, NewCodeA, 5, &dwWrite);
  26.         if (0 == dwRet || 0 == dwWrite)
  27.         {
  28.                 TRACE("啊,写入失败");
  29.         }
  30.         VirtualProtectEx(hProcess, pfFunc, 5, dwOldProtect, &dwTemp);
  31. }

  32. //关闭钩子的函数
  33. void HookOff()
  34. {
  35.         ASSERT(hProcess != NULL);

  36.         DWORD dwTemp = 0, dwOldProtect = 0, dwRet = 0, dwWrite = 0;

  37.         //恢复原API入口
  38.         VirtualProtectEx(hProcess, pfFunc, 5, PAGE_READWRITE, &dwOldProtect);
  39.         dwRet = WriteProcessMemory(hProcess, pfFunc, OldCodeA, 5, &dwWrite);
  40.         if (0 == dwRet || 0 == dwWrite)
  41.         {
  42.                 TRACE("啊,写入失败");
  43.         }
  44.         VirtualProtectEx(hProcess, pfFunc, 5, dwOldProtect, &dwTemp);
  45. }

  46. void Inject()
  47. {

  48.         if (!bIsInjected)
  49.         {
  50.                 bIsInjected = TRUE;//保证只调用1次

  51.                 if (pfFunc == NULL)
  52.                 {
  53.                         MessageBox(NULL, _T("cannot get Function"), _T("error"), 0);
  54.                         return;
  55.                 }

  56.                 _asm
  57.                 {
  58.                         lea edi, OldCodeA
  59.                         mov esi, pfFunc
  60.                                 cld
  61.                                 movsd
  62.                                 movsb
  63.                 }

  64.                 NewCodeA[0] = 0xe9;
  65.                 _asm
  66.                 {
  67.                         lea eax, FunctionAddress
  68.                         mov ebx, pfFunc
  69.                                 sub eax, ebx
  70.                                 sub eax, 5
  71.                                 mov dword ptr[NewCodeA + 1], eax
  72.                 }

  73.                 HookOn();
  74.         }
  75. }

  76. // CHookApiApp 初始化

  77. BOOL CHookApiApp::InitInstance()
  78. {
  79.         CWinApp::InitInstance();
  80.         hInst = AfxGetInstanceHandle();
  81.         DWORD dwPid = ::GetCurrentProcessId();
  82.         hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, 0, dwPid);

  83.         Inject();

  84.         return TRUE;
  85. }

  86. LRESULT CALLBACK MouseProc(
  87.         int nCode,      // hook code
  88.         WPARAM wParam,  // message identifier
  89.         LPARAM lParam   // mouse coordinates
  90.         )
  91. {
  92.         if (nCode == HC_ACTION)
  93.         {
  94.                 //将钩子所在窗口句柄发给主程序
  95.                 ::SendMessage(g_hWnd, UM_WNDTITLE, wParam, (LPARAM)(((PMOUSEHOOKSTRUCT)lParam)->hwnd));
  96.         }
  97.         return CallNextHookEx(hhk, nCode, wParam, lParam);
  98. }


  99. //安装钩子
  100. BOOL WINAPI HookApi(HWND hWnd,LPCWSTR ModuleName,LPCSTR FunctionName,PTR FunctionAddr)
  101. {
  102.         //获取函数
  103.         HMODULE hmod = ::LoadLibrary(ModuleName);
  104.         oldFunc = GetProcAddress(hmod, FunctionName);
  105.         pfFunc = (FARPROC)oldFunc;
  106.         g_hWnd = hWnd;
  107.         FunctionAddress = FunctionAddr;
  108.         hhk = ::SetWindowsHookEx(WH_MOUSE, MouseProc, hInst, 0);
  109.         if (hhk == NULL)
  110.         {
  111.                 return FALSE;
  112.         }
  113.         else
  114.         {
  115.                 return TRUE;
  116.         }
  117. }

  118. //卸载钩子
  119. VOID WINAPI UnHookApi()
  120. {
  121.         HookOff();

  122.         if (hhk != NULL)
  123.         {
  124.                 UnhookWindowsHookEx(hhk);
  125.                 FreeLibrary(hInst);
  126.         }
  127. }

  128. //dll退出时
  129. int CHookApiApp::ExitInstance()
  130. {
  131.         HookOff();

  132.         return TRUE;
  133. }
复制代码
回复 赞! 靠!

使用道具 举报

4

主题

31

回帖

155

积分

用户组: 小·技术宅

UID
7284
精华
0
威望
1 点
宅币
118 个
贡献
0 次
宅之契约
0 份
在线时间
10 小时
注册时间
2021-7-13
 楼主| 发表于 2021-7-14 11:28:55 | 显示全部楼层
本帖最后由 三叶草 于 2021-7-14 11:29 编辑

然后我在习惯性地按Ctrl+S时,也出现了此对话框:
360截图20210714112220305.jpg
回复 赞! 靠!

使用道具 举报

4

主题

31

回帖

155

积分

用户组: 小·技术宅

UID
7284
精华
0
威望
1 点
宅币
118 个
贡献
0 次
宅之契约
0 份
在线时间
10 小时
注册时间
2021-7-13
 楼主| 发表于 2021-7-14 11:31:16 | 显示全部楼层
还有一张:
360截图20210714112924727.jpg
回复

使用道具 举报

65

主题

117

回帖

1万

积分

用户组: 超级版主

OS与VM研究学者

UID
1043
精华
35
威望
789 点
宅币
8302 个
贡献
1094 次
宅之契约
0 份
在线时间
2069 小时
注册时间
2015-8-15
发表于 2021-7-14 20:07:00 | 显示全部楼层

你的HookApi函数定义成了

BOOL WINAPI HookApi(HWND hWnd,LPCWSTR ModuleName,LPCSTR FunctionName,PTR FunctionAddr)

其中ModuleNameFunctionName两个,一个用的是unicode字符串,一个用的是ansi字符串。VB6里调用API的时候会把字符串自动转换成ansi。
就是因为字符串编码问题导致你LoadLibrary失败。
如果你要让VB6按字符串传参数,那就必须全部用ansi字符串。换言之就是把ModuleName的类型换成LPCSTR
然后把LoadLibrary强行指定为LoadLibraryA或者GetModuleHandleA,只接受ansi字符串参数的版本。
如果不想改VC里的代码,那就在VB里把HookApi的代码定义成

Public Declare Function HookApi Lib "D:\HookApi.dll" (ByVal hWnd As Long, ByVal ModuleName As Long, ByVal FunctionName As String, ByVal FnctionAddr As Long) As Boolean

然后这么调用:

Call HookApi(Me.hWnd, StrPtr("user32"), "MessageBoxA", AddressOf My_MessageBox)
回复 赞! 靠!

使用道具 举报

4

主题

31

回帖

155

积分

用户组: 小·技术宅

UID
7284
精华
0
威望
1 点
宅币
118 个
贡献
0 次
宅之契约
0 份
在线时间
10 小时
注册时间
2021-7-13
 楼主| 发表于 2021-7-15 16:48:23 | 显示全部楼层
我按你说的做,结果还是不行,而且...
回复 赞! 靠!

使用道具 举报

4

主题

31

回帖

155

积分

用户组: 小·技术宅

UID
7284
精华
0
威望
1 点
宅币
118 个
贡献
0 次
宅之契约
0 份
在线时间
10 小时
注册时间
2021-7-13
 楼主| 发表于 2021-7-15 16:50:20 | 显示全部楼层
我用我另外一个程序调用了MessageBox,崩了,任务管理器都关不掉的那种
360截图20210715164720736.jpg
回复 赞! 靠!

使用道具 举报

65

主题

117

回帖

1万

积分

用户组: 超级版主

OS与VM研究学者

UID
1043
精华
35
威望
789 点
宅币
8302 个
贡献
1094 次
宅之契约
0 份
在线时间
2069 小时
注册时间
2015-8-15
发表于 2021-7-15 17:01:23 | 显示全部楼层
三叶草 发表于 2021-7-15 16:50
我用我另外一个程序调用了MessageBox,崩了,任务管理器都关不掉的那种

那就挂调试器看看崩哪里了呗,学一些windbg调试起来就简单多了
回复 赞! 靠!

使用道具 举报

4

主题

31

回帖

155

积分

用户组: 小·技术宅

UID
7284
精华
0
威望
1 点
宅币
118 个
贡献
0 次
宅之契约
0 份
在线时间
10 小时
注册时间
2021-7-13
 楼主| 发表于 2021-7-15 20:23:45 | 显示全部楼层
tangptr@126.com 发表于 2021-7-15 17:01
那就挂调试器看看崩哪里了呗,学一些windbg调试起来就简单多了

啊这,我不会winbdg
回复 赞! 靠!

使用道具 举报

55

主题

275

回帖

9352

积分

用户组: 管理员

UID
77
精华
16
威望
237 点
宅币
8217 个
贡献
251 次
宅之契约
0 份
在线时间
254 小时
注册时间
2014-2-22
发表于 2021-7-15 20:27:55 | 显示全部楼层
你HOOK自己进程内的函数为啥要用C写?VB一样可以调用VirtualProtect和WriteProcessMemory。

如果要HOOK其它进程内部的函数,那么地址必须要在其它进程里,不能是你进程里的地址。
回复 赞! 靠!

使用道具 举报

4

主题

31

回帖

155

积分

用户组: 小·技术宅

UID
7284
精华
0
威望
1 点
宅币
118 个
贡献
0 次
宅之契约
0 份
在线时间
10 小时
注册时间
2021-7-13
 楼主| 发表于 2021-7-15 22:50:59 | 显示全部楼层
我用的是全局钩子,VB写不了
回复 赞! 靠!

使用道具 举报

65

主题

117

回帖

1万

积分

用户组: 超级版主

OS与VM研究学者

UID
1043
精华
35
威望
789 点
宅币
8302 个
贡献
1094 次
宅之契约
0 份
在线时间
2069 小时
注册时间
2015-8-15
发表于 2021-7-16 03:23:05 | 显示全部楼层

我猜到你不会,所以用了“学”这个字。
https://docs.microsoft.com/en-us ... started-with-windbg
用windbg调试vb6程序的时候别忘了在编译前给项目勾选“创建符号调试信息”,它会额外生成一个pdb文件有助于你用windbg玩源码级调试。
Capture.PNG
回复 赞! 靠!

使用道具 举报

55

主题

275

回帖

9352

积分

用户组: 管理员

UID
77
精华
16
威望
237 点
宅币
8217 个
贡献
251 次
宅之契约
0 份
在线时间
254 小时
注册时间
2014-2-22
发表于 2021-7-16 05:27:36 | 显示全部楼层
三叶草 发表于 2021-7-15 22:50
我用的是全局钩子,VB写不了

你的VC-DLL到底是啥功能?我乍一看是API HOOK,怎么又看到了消息钩子?
回复 赞! 靠!

使用道具 举报

9

主题

177

回帖

1万

积分

用户组: 真·技术宅

UID
4293
精华
6
威望
441 点
宅币
8675 个
贡献
850 次
宅之契约
0 份
在线时间
338 小时
注册时间
2018-9-19
发表于 2021-7-16 09:55:43 | 显示全部楼层

VS可以附加调试到进程,选择附加到VB6IDE进程上,你就可以调试你自己写的dll,可以在源码里面下断点。
回复 赞! 靠!

使用道具 举报

9

主题

177

回帖

1万

积分

用户组: 真·技术宅

UID
4293
精华
6
威望
441 点
宅币
8675 个
贡献
850 次
宅之契约
0 份
在线时间
338 小时
注册时间
2018-9-19
发表于 2021-7-16 09:58:28 | 显示全部楼层
tangptr@126.com 发表于 2021-7-14 20:07
[md]你的`HookApi`函数定义成了
```C
BOOL WINAPI HookApi(HWND hWnd,LPCWSTR ModuleName,LPCSTR FunctionN ...

VB6还是tlb的方式调用C函数方便,我只需要在tlb内部声明LPCSTR和LPCWSTR,VB6调用就会自动根据参数传ANSI还是Unicode进去。
回复 赞! 靠!

使用道具 举报

4

主题

31

回帖

155

积分

用户组: 小·技术宅

UID
7284
精华
0
威望
1 点
宅币
118 个
贡献
0 次
宅之契约
0 份
在线时间
10 小时
注册时间
2021-7-13
 楼主| 发表于 2021-7-16 15:18:44 | 显示全部楼层
tangptr@126.com 发表于 2021-7-16 03:23
我猜到你不会,所以用了“学”这个字。
https://docs.microsoft.com/en-us/windows-hardware/drivers/deb ...

是这个吗?

工程1.pdb

81 KB, 下载次数: 0

回复 赞! 靠!

使用道具 举报

4

主题

31

回帖

155

积分

用户组: 小·技术宅

UID
7284
精华
0
威望
1 点
宅币
118 个
贡献
0 次
宅之契约
0 份
在线时间
10 小时
注册时间
2021-7-13
 楼主| 发表于 2021-7-16 15:19:54 | 显示全部楼层
美俪女神 发表于 2021-7-16 05:27
你的VC-DLL到底是啥功能?我乍一看是API HOOK,怎么又看到了消息钩子?

消息钩子只是个摆设,真正起作用的是Inject()
回复 赞! 靠!

使用道具 举报

55

主题

275

回帖

9352

积分

用户组: 管理员

UID
77
精华
16
威望
237 点
宅币
8217 个
贡献
251 次
宅之契约
0 份
在线时间
254 小时
注册时间
2014-2-22
发表于 2021-7-16 19:56:22 | 显示全部楼层
三叶草 发表于 2021-7-16 15:19
消息钩子只是个摆设,真正起作用的是Inject()

你具体要实现什么功能?
回复 赞! 靠!

使用道具 举报

4

主题

31

回帖

155

积分

用户组: 小·技术宅

UID
7284
精华
0
威望
1 点
宅币
118 个
贡献
0 次
宅之契约
0 份
在线时间
10 小时
注册时间
2021-7-13
 楼主| 发表于 2021-7-19 16:16:53 | 显示全部楼层
Hook Api,把线程注入到所有进程中,修改该进程Api的头部,使其跳转到我自己编写的函数中,拦截函数执行
回复 赞! 靠!

使用道具 举报

1111

主题

1651

回帖

7万

积分

用户组: 管理员

一只技术宅

UID
1
精华
244
威望
743 点
宅币
24239 个
贡献
46222 次
宅之契约
0 份
在线时间
2297 小时
注册时间
2014-1-26
发表于 2021-7-19 17:20:57 | 显示全部楼层
三叶草 发表于 2021-7-19 16:16
Hook Api,把线程注入到所有进程中,修改该进程Api的头部,使其跳转到我自己编写的函数中,拦截函数执行 ...

VC部分竟然写了个类。定睛一看,class CHookApiApp : public CWinApp。为了搞个Hook你这竟然用MFC,这是干屌?

void Inject(),我看到了内联汇编的操作,5字节Hook。这十分令人怀念Windows XP。强烈推荐了解Detours库,我就先不说什么你那个强行Hook的操作过于“线程不安全”了,槽点太多了。

然后我注意到:

FARPROC pfFunc = NULL;//指向原函数地址的远指针

(都1202年了还“FARPROC”,1986年就淘汰了的东西)

void Inject()里,你判断pfFunc为NULL时弹窗,内容是"cannot get Function"。

转到VB6的代码:
  1. Public Declare Function HookApi Lib "D:\HookApi.dll" (ByVal hWnd As Long, ByVal ModuleName As String, ByVal FunctionName As String, ByVal FnctionAddr As Long) As Boolean
复制代码
这是一个经典的VB6调用API时初学者容易遇到的坑。观察你的VC函数原型:
  1. BOOL WINAPI HookApi(HWND hWnd,LPCWSTR ModuleName,LPCSTR FunctionName,PTR FunctionAddr);
复制代码
你的ModuleName是宽字符,你的FunctionName不是,但是这两个在你的VB6声明里都是ByVal xxx As String,你的VB6程序无法区分其中两者。要知道:VB6调用API的时候,String类型会受到自动的Unicode转Ansi处理

因此你的 ModuleName 应该被定义为 ByVal ModuleName As Long ,然后传参的时候,传递你的模块名的字符串指针,使用 StrPtr() 传参,可以避免隐藏的字符串转换过程。

回复 赞! 靠!

使用道具 举报

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-4-23 18:07 , Processed in 0.051245 second(s), 31 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表