LGJ空间
登 陆
用户名:
密   码:
  注 册
公告栏
最新评论
asddasdasd
什么啊 点按钮 什么也不...
gf
dsfa
嗯,这年头不用MFC的人...
弟弟做得不错呀。。有长进...
德桑蒂斯
怎么提交到数据库里呢,提...
不错,好用
30天内热门
所有热门
JSP中使用poi操作Excel的几点注意事项(2766)
在textarea里显示图片,如何获取图片的值?(2741)
windows强制关机函数(2401)
一个字节,破解Word文档只读密码(1917)
进程隐藏技术详解(1914)
当系统插入了一个可移动磁盘的时候怎么等到这个消息?(1785)
让我们动起来吧!------网页脚本语言JavaScript(1732)
网页设计之超连接(1691)
如何让服务以administrator来创建某一进程(1674)
各位高手,谁有用钩子函数来监测文件操作的源代码?主要功能就是当对某一文件进行复制、剪贴、删除等操作时,会弹出一个窗口,提示你输入密码,然后进行文件操作。(1649)
如何通过WIN32 API取得当前登录用户的组(例如:Administrator、Guest等)?????(1559)
一个获取其他进程中列表控件内容的问题?(1548)
students(1409)
一个中国黑客致中国黑客和红客的公开信(1403)
揭开木马的神秘面纱(1285)
友情链接
在textarea里显示图片,如何获取图片的值?

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> New Document </TITLE>
<META NAME="Generator" CONTENT="EditPlus">
<META NAME="Author" CONTENT="">
<META NAME="Keywords" CONTENT="">
<META NAME="Description" CONTENT="">
</HEAD>

<BODY>
<textarea id="oText" cols="40" rows="8">有一些文字</textarea>
<script type="text/javascript">

        var oText = document.getElementById("oText");
        var oImg = document.createElement("IMG");
        oImg.src = "http://bbs.51js.com/images/default/logo.gif";
        oText.appendChild(oImg);
</script>
<script>
function pro(){
var oText = document.all.oText;
alert(oText.getElementsByTagName("IMG")[0].src);
}
</script>
<button onclick="pro();">button</button>
</BODY>
</HTML>

发表于:2006-11-16 0:05:38 | 作者:梁冠健 | 阅读:(2741) | 回复:(20)
让我们动起来吧!------网页脚本语言JavaScript

(1)在网页中弹出对话框

//在网页中输入下面代码:

alert("你好!JavaScript");

//看到的效果:

 

(2)在网页中弹出另外的网页

//在网页中输入类似下面的代码:

window.open("你要打开的网页","标题","width=宽度,height=高度,left=与显示器左边的距离,top=与显示器顶端的距离,scrollbars=是否要滚动条,resizable=是否可改变大小");

//看到的效果:


 
(3)在网页中弹出确认对话框

//在网页中输入类似下面的代码:

result=confirm("你喜欢JavaScript吗?");

if(result==true) alert("你为什么喜欢JavaScript?");  //条件语句,判断用户是点击了"确定" 还是点击了"取消"

else alert("为什么不喜欢JavaScript?");

//看到的效果:

(4)使用prompt()方法弹出对话框.

//在网页中输入类似下面的代码:

password=prompt("请输入你的密码");
if(password=="123456")alert("密码正确!");//判断用户输入的密码是否是123456,如果是就弹出“密码正确”对话框
else alert("密码错误!");//否则弹出“密码错误”对话框

//看到的效果


发表于:2006-4-16 20:05:49 | 作者:梁冠健 | 阅读:(1732) | 回复:(2)
Windows下DLL编程技术及应用 
摘 要: 本文介绍了DLL技术在Windows编程中的基本运用方法及应用,给出了直接内存访问及端口I/O的两个实用DLL的全部源代码。
关键词: DLL Windows编程 内存访问 I/O

一 、引 言
由于Windows为微机提供了前所未有的标准用户界面、图形处理能力和简单灵便的操作,绝大多数程序编制人员都已转向或正在转向Windows编程。在许多用户设计的实际应用系统的编程任务中,常常要实现软件对硬件资源和内存资源的访问,例如端口I/O、DMA、中断、直接内存访问等等 。若是编制DOS程序,这是轻而易举的事情,但要是编制Windows程序,尤其是WindowsNT环境下的程序,就会显得较困难。
因为Windows具有"与设备无关"的特性,不提倡与机器底层的东西打交道,如果直接用Windows的 API函数或I/O读写指令进行访问和操作,程序运行时往往就会产生保护模式错误甚至死机,更严重的情况会导致系统崩溃。那么在Windows下怎样方便地解决上述问题呢?用DLL(Dynamic Link Libraries)技术就是良好途径之一。
DLL是Windows最重要的组成要素,Windows中的许多新功能、新特性都是通过DLL来实现的,因此掌握它、应用它是非常重要的。其实Windows本身就是由许多的DLL组成的,它最基本的三大组成模块Kernel、GDI和User 都是DLL,它所有的库模块也都设计成DLL。凡是以.DLL、.DRV、.FON、.SYS和许多以.EXE为扩展名的系统文件都是DLL,要是打开Windows\System目录,就可以看到许多的DLL模块。尽管DLL在Ring3优先级下运行,仍是实现硬件接口的简便途径。DLL可以有自己的数据段,但没有自己的堆栈,使用与调用它的应用程序相同的堆栈模式,减少了编程设计上的不便;同时,一个DLL在内存中只有一个实例,使之能高效经济地使用内存;DLL实现的代码封装性,使得程序简洁明晰;此外还有一个最大的特点,即DLL的编制与具体的编程语言及编译器无关,只要遵守DLL的开发规范和编程策略,并安排正确的调用接口,不管用何种编程语言编制的DLL都具有通用性。例如在BC31中编制的DLL程序,可用于BC、VC、VB、Delphi等多种语言环境中。笔者在BC31环境下编译了Windows下直接内存访问和端口I/O两个DLL,用在多个自制系统的应用软件中,
运行良好。

二、DLL的建立和调用
DLL的建立及调用方法在许多资料上有详细的介绍,为了节省篇幅,在这里仅作一些
主要的概括。
1.DLL的建立
关于DLL的建立,有如下几个方面的要素是不可缺少和必须掌握的:
?. 入口函数LibMain( )
就象C程序中的WinMain( )一样,Windows每次加载DLL时都要执行LibMain( )函数,主要用来进行一些初始化工作。通常的形式是:



int FAR PASCAL LibMain(HINSTANCE hInstance,WORD wDataSeg,WORD
wHeapSize,LPSTR lpszCmdLine)
{
if(wHeapSize!=0) //使局部堆、数据段可移动
UnlockData(0); //解锁数据段
/*此处可进行一些用户必要的初始化工作*/
return 1; //初始化成功
}
?出口函数WEP( )
Windows从内存中卸载DLL时,调用相应的出口函数WEP( ),主要做一些清理工作,如释放占用的内存资源;丢弃某些字串、位图等资源;关闭打开的文件等等。
?自定义的输出函数
为了让位于不同内存段的应用程序进行远程调用,自定义的输出函数必须定义为远程函数(使用FAR关键字),以防使用近程指针而得到意外的结果;同时,加上PASCAL关键字可加快程序的运行速度,使代码简单高效,提高程序的运行速度。
?输出函数的引出方法
? 在DLL的模块定义文件中(.DEF)由EXPORTS语句对输出函数逐一列出。例如:
EXPORTS WEP @1 residentname //residentname可提高DLL效率和处理速度
PortIn @2
PortOut @3 //通常对所有输出函数附加系列号
? 在每个输出函数定义的说明中使用_export关键字来对其引出。
以上两种方法任选其中的一种即可,不可重复。后面的两个实例分别使用了上述两种不同的引出方式,请留意。

2.DLL的调用
加载DLL时,Windows寻找相应DLL的次序如下:
?.当前工作盘。
?Windows目录;GetWindowsDirectory( )函数可提供该目录的路径名。
?Windows系统目录,即System子目录;调用GetSystemDiretory( )函数可获得这个目录的路径名。
?DOS的PATH命令中罗列的所有目录。
?网络中映象的目录列表中的全部目录。

DLL模块中输出函数的调用方法:
不论使用何种语言对编译好的DLL进行调用时,基本上都有两种调用方式,即静态调用方式和动态调用方式。静态调用方式由编译系统完成对DLL的加载和应用程序结束时DLL卸载的编码(如还有其它程序使用该DLL,则Windows对DLL的应用记录减1,直到所有相关程序都结束对该DLL的使用时才释放它),简单实用,但不够灵活,只能满足一般要求。动态调用方式是由编程者用API函数加载和卸载DLL来达到调用DLL的目的,使用上较复杂,但能更加有效地使用内存,是编制大型应用程序时的重要方式。具体来说,可用如下的方法调用:
?.在应用程序模块定义文件中,用IMPORTS语句列出所要调用DLL的函数名。如:
IMPORTS MEMORYDLL.MemoryRead
MEMORYDLL.MemoryWrite
?让应用程序运行时与DLL模块动态链接



先用LoadLibrary加载DLL,再用GetProcAddress函数检取其输出函数的地址,获得其指针来调用。如:
HANDLE hLibrary;
FARPROC lpFunc;
int PortValue;
M
hLibrary=LoadLibrary("PORTDLL.DLL"); //加载DLL
if(hLibrary>31) //加载成功
{
lpFunc=GetProcAddress(hLibrary,"PortIn"); //检取PortIn函数地址
if(lpFunc!=(FARPROC)NULL) //检取成功则调用
PortValue=(*lpFunc)(port); //读port端口的值
FreeLibrary(hLibrary); //释放占用的内存
}
M

三、DLL应用实例源程序
1.直接内存访问的DLL源代码
//.DEF文件
LIBRARY MEMORYDLL
DESCRIPTION ’DLL FOR MEMORY_READ_WRITE ’
EXETYPE WINDOWS
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE SINGLE
HEAPSIZE 1024 //DLL无自己的堆栈,故没有STACKSIZE语句
EXPORTS WEP @1 residentname
ReadMemory @2
WriteMemory @3

//.CPP文件
#include <windows.h>

int FAR PASCAL LibMain(HINSTANCE hInstance,WORD wDataSeg,WORD
wHeapSize,LPSTR lpszCmdLine)
{
if(wHeapSize!=0)
UnlockData(0);
return 1;
}

int FAR PASCAL MemoryRead(unsigned int DosSeg,unsigned int DosOffset)
{
WORD wDataSelector,wSelector;
char far *pData;
char value;
wDataSelector=HIWORD((DWORD)(WORD FAR *)&wDataSelector);
wSelector=AllocSelector(wDataSelector); //分配选择器
SetSelectorLimit(wSelector,0x2000); //置存取界限
SetSelectorBase(wSelector,(((DWORD)DosSeg)<<4)+(DWORD)DosOffset); //置基地址
pData=(char far *)((DWORD)wSelector<<16);
value=*pData;
FreeSelector(wSelector); //释放选择器
return (value);
}



void FAR PASCAL MemoryWrite(unsigned int DosSeg,unsigned int DosOffset,char Data)
{
WORD wDataSelector,wSelector;
char far *pData;
wDataSelector=HIWORD((DWORD)(WORD FAR *)&wDataSelector);
wSelector=AllocSelector(wDataSelector);
SetSelectorLimit(wSelector,0x2000);
SetSelectorBase(wSelector,(((DWORD)DosSeg)<<4)+(DWORD)DosOffset);
pData=(char far *)((DWORD)wSelector<<16);
*pData=Data;
FreeSelector(wSelector);
}

int FAR PASCAL WEP(int nParam)
{
return 1;
}

2.端口读写I/O的DLL源代码
//.DEF文件
LIBRARY PORTDLL
DESCRIPTION ’DLL FOR PORT_IN_OUT ’
EXETYPE WINDOWS
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE SINGLE
HEAPSIZE 1024

//.CPP文件
#include <windows.h>
#include <dos.h>

int FAR PASCAL LibMain(HINSTANCE hInstance,WORD wDataSeg,WORD
wHeapSize,LPSTR lpszCmdLine)
{
if(wHeapSize!=0)
UnlockData(0);
return 1;
}

int FAR PASCAL _export PortOut(int port,unsigned char value)
{
outp(port,value);
return 1;
}

int FAR PASCAL _export PortIn(int port)
{
int result;
result=inp(port);
return (result);
}

int FAR PASCAL _export WEP(int nParam)
{
return 1;
}


分别将上面两个实例的.DEF文件和.CPP文件各自组成一个.PRJ文件,并进行编译链接成.EXE或.DLL文件就可以在应用程序中对其进行调用。

四、结 束 语
在上面,我们利用DLL技术方便地实现了Windows环境下对内存的直接访问和端口I/O的访问,仿效这两个例子,还可以编制出更多的适合自己应用系统所需的DLL,如用于数据采集卡的端口操作及扩展内存区访问、视频区缓冲区及BIOS数据区操作等许多实际应用的编程任务中。必要时只需直接更新DLL,而用不着对应用程序本身作任何改动就可以对应用程序的功能和用户接口作较大的改善,实现版本升级。因此,掌握好DLL技术对Windows程序开发者很有裨益。
发表于:2006-4-4 10:54:42 | 作者:梁冠健 | 阅读:(1188) | 回复:(0)
一个中国黑客致中国黑客和红客的公开信
所有中国黑客和红客,我的同胞们:

首先声明,我的计算机软件技术、黑客功底,可能不会比你们任何人差:

我通读过 MINIX,TCP/IP,BSD,LINUX, PL1的源码,我拿过中国高级程序员证书,SUN 的JAVA证书,精通VC和UNIX,对缓冲区溢出,病毒,DDK等均有研究,所以我想我有资格对你们说几句话。

(如果我提到的一些计算机名词和人名,你们居然不知道,那只能证明你们的无知,和不配称为黑客。)

如果是真正的黑客,他会知道

1.发明TCP/IP的是美国人 。

2. LINUX的作者,linus大侠现在也在美国工作 。

3. OPEN SOURCE的开创人 STALLMAN 也是美国人,他提倡软件不分国界的自由的精神 。

4. FREE BSD 的作者是美国人,他的SOURCE 让真正的黑客受惠

5.世界级软件科学大师 tanabaom,也是美国的客座教授,他的minix, ameba和教材教育了全世界几代黑客。

提到这些,不是崇美,不是恐美,只想证明:

1.很多大师级的美国黑客,他们的理念恰恰是自由、开放、无国界;他们的自由软件,开放源码,是与政治无关的,是超越国界的,给全世界人们带来福音。

2.真正的黑客精神,如stallman所说,是要让人类超越计算机,成为计算机的主宰,从而成为自由的。

所有的中国黑客和红客,我的同胞们:

当你们正通过下载美国人写的黑客工具,来攻击美国网络,并且乐此不疲,以为这就是爱国行动的时候,是否想过:

此时此刻,印度的软件人士,正在努力提高软件技术,他们的软件水平、软件产业已经超越了中国;难道我们不应该痛苦地承认这个现实,并且奋起直追吗?

中国发明了火药,但是缺少研究精神,结果是被西方人研究改进了以后打中国,这样的教训还少吗?

中国向来不缺爱国热情,但是我们缺少对科技的认真研究精神,知耻而后勇的追赶精神。难道我们不愿意承认这一点吗?

从战术上来说,过早暴露自己的实力是不聪明的;冒昧地问一句,如果真的战争爆发了,您的黑客技术完全掌握好了吗,您已经为那一天的到来在进行技术储备吗?

您有没有想向那些真正为中国科技做出杰出贡献的科学家如钱学森学习呢?

所有的中国黑客和红客,我的同胞们:

请把你们的聪明才智用到真正提高你们的水平,对国家的强大有帮助的地方吧:

如果您愿意对国家有所贡献:

1.中国的863计划中有一个重点研究项目: 并行计算,分布计算,向量计算。您愿意研究它吗?

2. 作为现代通讯技术的一个根本数学基础,大合数的快速因子分解,还是一个难题。您愿意研究它吗?

如果您想提高技术,对中国的软件技术有所贡献:

1.研究 VC,JAVA

2.研究数据结构,去考高级程序员

3. 研究操作系统,读minix source code

4. 研究tcp/ip, rfc文档

5. 通读linux, 才算达到黑客境界

6. 学习 UML,ROSE,软件工程,达到系统分析员水平。

如果您对提高中国的科技有兴趣,去研究生物基因,材料技术(纳米技术),计算机技术,航天技术……

我的同胞们,我愿大声呐喊:

一个真正的民族主义者,不是义和团,不是太平天国,不是闭关锁国,不是盲目仇外,不是不敢正视自己民族和文化的丑陋和缺点。

真正的民族主义者是成熟的、清醒的、理智的、务实的民族主义。真正的民族主义者不是种族主义者,不是极端份子,不是战争狂人。

真正的民族主义者以追求本民族——中华民族的利益最大化为目标、准则、信念。判断一个人是不是真正的民族主义者,判断标准很简单:看他是给本民族的整体利益带来好处,还是损害民族利益。真正的民族主义者最务实,因为他知道坚持原则,同时又懂得策略。让我们成为真正的顶尖黑客!让我们成为真正的民族主义者!
发表于:2006-4-4 10:47:17 | 作者:梁冠健 | 阅读:(1403) | 回复:(9)
在windows98下自动启动程序的10种方法
1. Autostart 文件
C:\windows\start menu\programs\startup {chinese/english}
C:\windows\Menu D閙arrer\Programmes\D閙arrage {french}
在注册表中的位置: HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell
Folders Startup="C:\windows\start menu\programs\startup"
所以它将很容易被程序更改

2. Win.ini
[windows]
load=file.exe
run=file.exe

3. System.ini [boot]
Shell=Explorer.exe file.exe

4. c:\windows\winstart.bat
看似平常,但每次都重新启动

5. Registry键
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunServices]
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunServicesOnce]
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run]
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce]
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run]
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce]
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunServices]

6. c:\windows\wininit.ini
一旦运行就被windows删除,安装的setup程序常用
Example: (content of wininit.ini)
[Rename]
NUL=c:\windows\picture.exe
例子:将c:\windows\picture.exe设置为NUL, 表示删除它,完全隐蔽的执行!

7. Autoexec.bat
在DOS下每次自启动

8. Registry Shell Spawning (使用过Subseven吗?看看吧)
[HKEY_CLASSES_ROOT\exefile\shell\open\command] @="\"%1\" %*"
[HKEY_CLASSES_ROOT\comfile\shell\open\command] @="\"%1\" %*"
[HKEY_CLASSES_ROOT\batfile\shell\open\command] @="\"%1\" %*"
[HKEY_CLASSES_ROOT\htafile\Shell\Open\Command] @="\"%1\" %*"
[HKEY_CLASSES_ROOT\piffile\shell\open\command] @="\"%1\" %*"
[HKEY_LOCAL_MACHINE\Software\CLASSES\batfile\shell\open\command] @="\"%1\" %*"
[HKEY_LOCAL_MACHINE\Software\CLASSES\comfile\shell\open\command] @="\"%1\" %*"
[HKEY_LOCAL_MACHINE\Software\CLASSES\exefile\shell\open\command] @="\"%1\" %*"
[HKEY_LOCAL_MACHINE\Software\CLASSES\htafile\Shell\Open\Command] @="\"%1\" %*"
[HKEY_LOCAL_MACHINE\Software\CLASSES\piffile\shell\open\command] @="\"%1\" %*"

这些"%1 %*"需要被赋值, 如果将其改为 "server.exe %1 %*",
server.exe将在每次启动时被执行,这些exe/pif/com/bat/hta等文件都可被执行

9. Icq Inet
[HKEY_CURRENT_USER\Software\Mirabilis\ICQ\Agent\Apps\test]
"Path"="test.exe"
"Startup"="c:\\test"
"Parameters"=""
"Enable"="Yes"

[HKEY_CURRENT_USER\Software\Mirabilis\ICQ\Agent\Apps\
当icq发现网络连接时,将被执行(我使用的icq2000b的键值有所不同,但您可以自行查找)
您发现OICQ有这方面的问题吗?^_^...

9. 杂项说明
找找以下的键值:
[HKEY_LOCAL_MACHINE\Software\CLASSES\ShellScrap]
@="Scrap object" "NeverShowExt"=""

NeverShowExt 键 可以隐藏SHS文件的扩展名.shs
如果你将一个文件改名为:"abc.jpg.shs" 它只显示"abc.jpg"
如果你的注册表里有很多NeverShowExt键值,删除他们。
注意:
这些方法不能全部适应Win2K,但您可以自行检测。
发表于:2006-4-4 10:44:06 | 作者:梁冠健 | 阅读:(1102) | 回复:(0)
利用HOOK拦截封包原理
截获API是个很有用的东西,比如你想分析一下别人的程序是怎样工作的。这里我介绍一下一种我自己试验通过的方法。
首先,我们必须设法把自己的代码放到目标程序的进程空间里去。Windows Hook可以帮我们实现这一点。SetWindowsHookEx的声明如下:
HHOOK SetWindowsHookEx(
int idHook, // hook type
HOOKPROC lpfn, // hook procedure
HINSTANCE hMod, // handle to application instance
DWORD dwThreadId // thread identifier
);
具体的参数含义可以翻阅msdn,没有msdn可谓寸步难行。
这里Hook本身的功能并不重要,我们使用它的目的仅仅只是为了能够让Windows把我们的代码植入别的进程里去。hook Type我们任选一种即可,只要保证是目标程序肯定会调用到就行,这里我用的是WH_CALLWNDPROC。lpfn和hMod分别指向我们的钩子代码及其所在的dll,dwThreadId设为0,表示对所有系统内的线程都挂上这样一个hook,这样我们才能把代码放到别的进程里去。

之后,我们的代码就已经进入了系统内的所有进程空间了。必须注意的是,我们只需要截获我们所关心的目标程序的调用,因此还必须区分一下进程号。我们自己的钩子函数中,第一次运行将进行最重要的API重定向的工作。也就是通过将所需要截获的API的开头几个字节改为一个跳转指令,使其跳转到我们的API中来。这是最关键的部分。这里我想截三个调用,ws2_32.dll中的send和recv、user32.dll中的GetMessageA。

DWORD dwCurrentPID = 0;
HHOOK hOldHook = NULL;
DWORD pSend = 0;
DWORD pRecv = 0;
GETMESSAGE pGetMessage = NULL;

BYTE btNewBytes[8] = { 0x0B8, 0x0, 0x0, 0x40, 0x0, 0x0FF, 0x0E0, 0 };
DWORD dwOldBytes[3][2];

HANDLE hDebug = INVALID_HANDLE_value;

LRESULT CALLBACK CallWndProc( int nCode, WPARAM wParam, LPARAM lParam )
{
DWORD dwSize;
DWORD dwPIDWatched;
HMODULE hLib;

if( dwCurrentPID == 0 )
{
dwCurrentPID = GetCurrentProcessId();
HWND hwndMainHook;
hwndMainHook = ::FindWindow( 0, "MainHook" );
dwPIDWatched = ::SendMessage( hwndMainHook, (WM_USER+100), 0, 0 );
hOldHook = (HHOOK)::SendMessage( hwndMainHook, (WM_USER+101), 0, 0 );

if( dwCurrentPID == dwPIDWatched )
{
hLib = LoadLibrary( "ws2_32.dll" );
pSend = (DWORD)GetProcAddress( hLib, "send" );
pRecv = (DWORD)GetProcAddress( hLib, "recv" );

::ReadProcessMemory( INVALID_HANDLE_value, (void *)pSend, (void *)dwOldBytes[0], sizeof(DWORD)*2, &dwSize );
*(DWORD *)( btNewBytes + 1 ) = (DWORD)new_send;
::WriteProcessMemory( INVALID_HANDLE_value, (void *)pSend, (void *)btNewBytes, sizeof(DWORD)*2, &dwSize );

::ReadProcessMemory( INVALID_HANDLE_value, (void *)pRecv, (void *)dwOldBytes[1], sizeof(DWORD)*2, &dwSize );
*(DWORD *)( btNewBytes + 1 ) = (DWORD)new_recv;
::WriteProcessMemory( INVALID_HANDLE_value, (void *)pRecv, (void *)btNewBytes, sizeof(DWORD)*2, &dwSize );

hLib = LoadLibrary( "user32.dll" );
pGetMessage = (GETMESSAGE)GetProcAddress( hLib, "GetMessageA" );
::ReadProcessMemory( INVALID_HANDLE_value, (void *)pGetMessage, (void *)dwOldBytes[2], sizeof(DWORD)*2, &dwSize );
*(DWORD *)( btNewBytes + 1 ) = (DWORD)new_GetMessage;
::WriteProcessMemory( INVALID_HANDLE_value, (void *)pGetMessage, (void *)btNewBytes, sizeof(DWORD)*2, &dwSize );

hDebug = ::CreateFile( "C:\\Trace.log", GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0 );
}
}

if( hOldHook != NULL )
{
return CallNextHookEx( hOldHook, nCode, wParam, lParam );
}

return 0;
}

上面的钩子函数,只有第一次运行时有用,就是把三个函数的首8字节修改一下(实际上只需要7个)。btNewBytes中的指令实际就是
mov eax, 0x400000
jmp eax
这里的0x400000就是新的函数的地址,比如new_recv/new_send/new_GetMessage,此时,偷梁换柱已经完成。再看看我们的函数中都干了些什么。以GetMessageA为例:

BOOL _stdcall new_GetMessage( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax )
{
DWORD dwSize;
char szTemp[256];
BOOL r = false;

//Watch here before it‘s executed.
sprintf( szTemp, "Before GetMessage : HWND 0x%8.8X, msgMin 0x%8.8X, msgMax 0x%8.8x \r\n", hWnd, wMsgFilterMin, wMsgFilterMax );
::WriteFile( hDebug, szTemp, strlen(szTemp), &dwSize, 0 );
//Watch over

// restore it at first
::WriteProcessMemory( INVALID_HANDLE_value, (void *)pGetMessage, (void *)dwOldBytes[2], sizeof(DWORD)*2, &dwSize );

// execute it
r = pGetMessage( lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax );

// hook it again
*(DWORD *)( btNewBytes + 1 ) = (DWORD)new_GetMessage;
::WriteProcessMemory( INVALID_HANDLE_value, (void *)pGetMessage, (void *)btNewBytes, sizeof(DWORD)*2, &dwSize );

//Watch here after it‘s executed
sprintf( szTemp, "Result of GetMessage is %d.\r\n", r );
::WriteFile( hDebug, szTemp, strlen( szTemp ), &dwSize, 0 );
if( r )
{
sprintf( szTemp, "Msg : HWND 0x%8.8X, MSG 0x%8.8x, wParam 0x%8.8X, lParam 0x%8.8X\r\nTime 0x%8.8X, X %d, Y %d\r\n",
lpMsg->hwnd, lpMsg->message,
lpMsg->wParam, lpMsg->lParam, lpMsg->time,
lpMsg->pt.x, lpMsg->pt.y );
::WriteFile( hDebug, szTemp, strlen( szTemp ), &dwSize, 0 );
}
strcpy( szTemp, "\r\n" );
::WriteFile( hDebug, szTemp, strlen( szTemp ), &dwSize, 0 );

//Watch over

return r;
}

先将截获下来的参数,写入到一个log文件中,以便分析。然后恢复原先保留下来的GetMessageA的首8字节,然后执行真正的GetMessageA调用,完毕后再将执行结果也写入log文件,然后将GetMessageA的执行结果返回给调用者。
整个截获的过程就是这样。你可以把其中的写log部分改成你自己想要的操作。这里有个不足的地方是,截获动作是不能够并发进行的,如果目标进程是多线程的,就会有问题。解决办法是,可以在每次new_GetMessage中加入一个CriticalSection的锁和解锁,以使调用变为串行进行,但这个我没有试验过。
发表于:2006-4-4 10:38:44 | 作者:梁冠健 | 阅读:(969) | 回复:(0)
1234