关于DLL内部函数的参数在调用时动态修改的问题

清晨曦月
博客专家认证
2009-05-28 11:18:02
是酱紫的,写了一个DLL用来HOOK一个API函数,我需要修改它的返回值,但是修改时要根据调用程序的设定来修改。

于是,在DLL中定义了一个全局变量:
double Num;

然后,搞了一个函数来修改这个数值:
extern "C" _declspec(dllexport) void __stdcall SetNum(double NewNum)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
Num=NewNum;
}

好嘛,已测试,发现只要我的程序调用SetNum,就崩溃了,还无法调试……告诉我无法调试一个已终止的进程,我晕~~~~~~~~

后来加了一个这个:
CRITICAL_SECTION _cs;
先初始化,然后在SetNum和mYFunction中对Num读写的语句前后分别加了这:
EnterCriticalSection(&_cs);
//和Num有关的代码
LeaveCriticalSection(&_cs);
测试发现还是同样的错误嘛…而且在SetNum中调用AfxMessageBox的时候,Num=NewNum;前后都正常弹出啊………看来是我认识不够。。。。。。。。

请高人指点二三……问题出在什么地方,我得咋整才能实现这个数据的“动态修改”呢?
...全文
302 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
清晨曦月 2009-05-30
  • 打赏
  • 举报
回复
问题解决了。。。。用自己的方法。。。

可能是我开始叙述的时候有一点问题,就是…………我是VB写主程序,VC写DLL,而注入,DLL内的函数调用,包括我想修改的数值,都是用的远线程……又用互斥体试了一下,还是不成功。。。。于是只好动了点“外科手段”,搞定。


感谢各位的回答,我感觉就是我叙述的不清楚,现在整理一下。。
#pragma data_seg ("SM")
double Num = 1.0 ; //倍数
#pragma data_seg()
是需要MFC支持的,可我主程序是VB.NET,所以……不知道MFC实现这个的机理,恐怕无法使用

共享内存那个找不到,可能是我以前写的VB.NET代码有一些问题,再加上对LPCWSTR认识不够深入,可能陷入了A和U编码当中,没仔想。

最后我实现的方法是DLL提供一个函数GetNumAddress,返回&NUM,即向主程序公开DLL中NUM数值的地址,远线程调用该函数取得其返回值,然后……全世界都知道了,万事具备……要权限有权限,要句柄有句柄,要地址有地址,想写什么就写吧。


改天再学VC,还是先写工程……
maple_zhj 2009-05-29
  • 打赏
  • 举报
回复


该说的.楼上几位说得差不多了.


我只补充一句: 
使用共享数据段时,一定要对变量进行初始化,也就是定义时赋值。!!!
码侬 2009-05-29
  • 打赏
  • 举报
回复
学习
biweilun 2009-05-29
  • 打赏
  • 举报
回复
不明白楼主的意思,现在想做什么?
清晨曦月 2009-05-29
  • 打赏
  • 举报
回复
我也非常困惑啊,,,咋就找不到呢。。。。。正在尝试

void ReadNum()
{
double *sheardata = NULL;
HANDLE hFile = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, (LPCWSTR)_dwIdNew);//最后一个参数为名字,必须与创建的相同
if(hFile != NULL)
{
LPVOID lpView = MapViewOfFile(hFile, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);//将内存映射文件的一个视图映射到当前的地址空间
if ((int *)lpView != NULL)
{
sheardata = (double*)lpView; //读
}
UnmapViewOfFile((LPVOID) lpView);
}
CloseHandle(hFile);
if ((double *)sheardata != NULL)
{
Num=1;
}
else
{
Num=*sheardata;
}
}
都快疯掉啦
biweilun 2009-05-29
  • 打赏
  • 举报
回复
多进程共享一个DLL中的变量就是这么干的。
biweilun 2009-05-29
  • 打赏
  • 举报
回复
LS几位说的不错,为什么不行呢?
清晨曦月 2009-05-29
  • 打赏
  • 举报
回复
就是差这个问题。。。哎,直接败了。。。可我总不能固定那个NUM到一个数值上啊,要是那样不就不可调节了么……就没有多大意义了。。谁也不愿意程序一直运行在较快或较慢的非正常状态啊。。。。
清晨曦月 2009-05-29
  • 打赏
  • 举报
回复
还是不行的。。。。。我试了…………嗷嗷


替换函数如下:
DWORD WINAPI mGetTickCount()
{
DWORD nReturn = 0;
DWORD ret ;
HookOffOne(&StrHook);
nReturn = GetTickCount();
HookOnOne(&StrHook);
//(当前返回值-上次返回值)*倍数+上一次的修改值
ret =(nReturn-nReturnBack)*Num+NumBack;
NumBack = ret;
nReturnBack = nReturn;
return ret;
}

前面加了这个:

#pragma data_seg("HookGetTickCountNum")
double Num = 0.0;
#pragma data_seg()
#pragma comment(linker,"/SECTION:HookGetTickCountNum,RWS")


可是我的主程序发现不了名为HookGetTickCountNum的共享内存,而是创建了一个。。。代码是这样的
''' <summary>
''' 初始化共享内存
''' </summary>
''' <param name="strName">共享内存名称</param>
''' <param name="lngSize">共享内存大小</param>
''' <returns></returns>
Public Function Init(ByVal strName As String, ByVal lngSize As Long) As Integer
If lngSize <= 0 OrElse lngSize > &H800000 Then
lngSize = &H800000
End If
m_MemSize = lngSize
If strName.Length > 0 Then
'创建内存共享体(INVALID_HANDLE_VALUE)
m_hSharedMemoryFile = CreateFileMapping(INVALID_HANDLE_VALUE, IntPtr.Zero, CUInt(PAGE_READWRITE), 0, CUInt(lngSize), strName)
If m_hSharedMemoryFile = IntPtr.Zero Then
m_bAlreadyExist = False
m_bInit = False
Return 2
'创建共享体失败
Else
If GetLastError() = ERROR_ALREADY_EXISTS Then
'已经创建
m_bAlreadyExist = True
Else
'新创建
m_bAlreadyExist = False
End If
End If
'---------------------------------------
'创建内存映射
m_pwData = MapViewOfFile(m_hSharedMemoryFile, FILE_MAP_WRITE, 0, 0, CUInt(lngSize))
If m_pwData = IntPtr.Zero Then
m_bInit = False
CloseHandle(m_hSharedMemoryFile)
Return 3
'创建内存映射失败
Else
m_bInit = True
If m_bAlreadyExist = False Then
'初始化
End If
End If
'----------------------------------------
Else
Return 1
'参数错误
End If
Return 0
'创建成功
End Function

当我进行初始化共享内存的时候,发现代码创建了一个新的共享内存。。也就是代码运行了m_bAlreadyExist = False……

上面函数是根据共享内存名称创建或返回已有共享内存的函数。流程就是直接创建共享内存,根据返回值和错误代码进一步处理,返回值为0时说明成功,返回值是1时证明输入了错误参数,返回值是2时说明创建函数失败,返回值是3时说明映射失败(即已经有这个名称的内存存在了,但是映射时未成功。
yyunffu 2009-05-29
  • 打赏
  • 举报
回复
这个问题似乎和共享变量没什么关系啊,进程本身修改自己拷贝的返回值,应该不会有问题。
另外,你的变量保护又是针对单个进程中线程之间数据同步,似乎并不是进程之间共享变量问题啊。

那个API返回值是否可写?有没有什么条件?
jingzhongrong 2009-05-29
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 zcsor 的回复:]
晕了,高了半天,不成…………

我在CPP里加入这个

#pragma data_seg ("SM")
double Num = 1.0 ; //倍数
#pragma data_seg()

在DEF里加入这个

; HookGetTickCount.def : 声明 DLL 的模块参数。

LIBRARY      "HookGetTickCount"

EXPORTS
; 此处可以是显式导出
Init
Hook
UnHook

SECTIONS
SM READ WRITE SHARED


然后去主程序里打开共享内存,发现没有名字叫SM的共享内存啊。。。。。狂倒
[/Quote]

#pragma comment(linker,"/SECTION:SharedData,RWS")
jingzhongrong 2009-05-29
  • 打赏
  • 举报
回复
1、添加共享节,还是使用SetNum来修改Num就可以了。另外共享节需要在DEF文件中添加
SECTIONS SharedData READ WRITE SHARE

2、可以还是使用CriticalSection来保护变量。
清晨曦月 2009-05-29
  • 打赏
  • 举报
回复
晕了,高了半天,不成…………

我在CPP里加入这个

#pragma data_seg ("SM")
double Num = 1.0 ; //倍数
#pragma data_seg()

在DEF里加入这个

; HookGetTickCount.def : 声明 DLL 的模块参数。

LIBRARY "HookGetTickCount"

EXPORTS
; 此处可以是显式导出
Init
Hook
UnHook

SECTIONS
SM READ WRITE SHARED


然后去主程序里打开共享内存,发现没有名字叫SM的共享内存啊。。。。。狂倒
清晨曦月 2009-05-29
  • 打赏
  • 举报
回复

[Quote=引用 1 楼 jingzhongrong 的回复:]
如果是共享的变量,要放在共享节里面。

C/C++ code#pragma data_seg("SharedData")
double Num = 0.0;
#pragma data_seg()
#pragma comment(linker,"/SECTION:SharedData,RWS")
[/Quote]

这……也就是说用共享内存吧,如果我想用VB写主程序来操作这个量,那么需要使用API函数打开名为SharedData的共享内存而后写入需要的NUM值对吧……

那就涉及到另外一个问题了……

[Quote=引用 5 楼 pangqi022 的回复:]
1楼的做法 加上 命名的护斥 对变量进行保护
[/Quote]

这个我还是不了解,应该如何实现呢?能否根据PID创建共享名呢,也就是说,每个不同的进程加载我的DLL后,DLL创建不同名称的共享内存?各位高手都是如何解决的啊……


[Quote=引用 6 楼 fishion 的回复:]
你直接在替换API的处理函数里替换返回值,而不用SetNum,这样行不
[/Quote]

我就是这样处理的,在替换函数里进行计算,虽然有多个变量,但是其他变量都是在DLL内部计算的,需要外部设置的只有NUM这一个。。。
fishion 2009-05-29
  • 打赏
  • 举报
回复
你直接在替换API的处理函数里替换返回值,而不用SetNum,这样行不
pangqi022 2009-05-29
  • 打赏
  • 举报
回复
1楼的做法 加上 命名的护斥 对变量进行保护
清晨曦月 2009-05-29
  • 打赏
  • 举报
回复
不行了…………完蛋了
大家帮忙看看啊,这个咋回事 啊

void ReadNum() ;
HANDLE m_hReceiveMap;
LPBYTE m_lpbReceiveBuf;
void ReadNum()
{
m_hReceiveMap = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE,(LPCWSTR)"SM");
//GetLastError()=2;
if (m_hReceiveMap == NULL)
return;
m_lpbReceiveBuf = (LPBYTE)MapViewOfFile(m_hReceiveMap,FILE_MAP_ALL_ACCESS,0,0,8);
if (m_lpbReceiveBuf == NULL)
{
CloseHandle(m_hReceiveMap);
m_hReceiveMap=NULL;
}
memcpy(&Num,m_lpbReceiveBuf,8);
}

打开共享内存失败啊,我用VB.NET搞了一个创建,测试了一下,可以正常打开,可怎么一到VC++.NET就不成了啊。。。疯掉了
清晨曦月 2009-05-29
  • 打赏
  • 举报
回复
就是写DLL,HOOK了个API,需要动态修改DLL里面的一个数据。

我把我的进程和DLL所在进程都提了权限有关系吗?
b43ok 2009-05-29
  • 打赏
  • 举报
回复
Dll里全局变量数据会因为不同的程序加载而丢失
所以通常都会用1楼的办法来解决这个问题
greatws 2009-05-29
  • 打赏
  • 举报
回复
用1楼的方法就行了,设置一个共享区段,这个共享区段是所有加载这个dll的进程所共享的。

还有,如果要hook的话,不要用mfc的dll,要使用标准dll。
加载更多回复(1)

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧