高级话题:用ASM直接调用没有参数信息的dll库函数!

作者:不及格的程序员-八神

1. 背景资料

通常开发者获取到的通用dll函数库都会有说明文件,里面对dll库中公开的函数都会有api接口说明,比如函数的名称,返回值,参数类型以及参数的数量.

但是有时开发者也会找到一些dll库函数,这些库函数只能获取到函数名称,而没有关于函数的参数信息.

这种dll一般是来自第三方的,或是偷来的(我的项目中就是属于此类,我知道这个dll函数的功能很不错,我就是想将它嵌入到我的程序中.)).

对于前者,具有资料完备API编程信息,我们可以在c++,vb或.NET平台中轻松编写调用接口来执行dll中的函数,而后者由于没有参数信息,想调用就不那么简单了.

通常系统自带的dll函数库都会有api说明,或者也可以通过某些工具来获取dll库中的函数描述信息.

可是一些第三方的dll函数可能不会将函数信息写到dll中,这样我们就不能够获取参数信息了,也就无法调用了,真的没办法吗?

 

2. 解决办法

即然没有参数信息就没有办法声明函数的调用接口,不过没关系.

我想到一种简单的方式:用汇编语言来直接调用.

首先要有完整的第三方程序,先看看第三方程序在汇编语言层面上是如何调用函数的(通过反汇编).

通过调试软件(如:windbg,od,softace等)将第三方的程序运行起来,然后在我们需要的那个dll模块函数上加断点,分析它的汇编码.

其实很简单的,如果函数需要参数,那就看看它是通过栈的方式传的参数还是通过寄存器来传的参数.

一般汇编语言中参数都是传的参数地址,而不是值.另外传递参数的规则也要弄清.

如果传参方式是栈方式传参数,还要区分是调用者清除栈还是被调用者清除栈.

比如下面代码是调用md5加密,我就是用栈方式传递两个指针参数给函数.

    mov eax,dword ptr [cb] //传入待加密字符串地址

    push eax //参数2 入栈

    mov eax,dword ptr [result] //反回值字符串地址

    push eax //参数1 入栈

    call pFun //执行函数

结果result里就是我们加密后的结果了.

上面代码使用的是调用者清除栈方式,而清除栈方式是被调用者清除栈(通过反汇编可以发现指定函数里是使用哪种清栈方式.): 如果需要我们清除栈,那就在上面代码的最后写 add esp,8 代表释放两个指针参数的空间8个字节.

关于函数清栈方式参见我的另一篇随笔:函数的可变数目参数 与 栈

 

3. 如何加载dll与函数地址

 我使用win32 api 来加载dll库与函数地址,使用方式:

HINSTANCE dll = LoadLibrary(L"d:\\*******.dll");

FARPROC pFun = GetProcAddress(dll,"要调用的函数名称");

_asm

{

  mov eax,dword ptr [cb]

  push eax

  mov eax,dword ptr [result] 

  push eax

  call pFun

}

 

4. 注意事项

需要特别注意的是,对于(传入的/返回的)参数指针指向的数据区域大小需要多次试验,因为有时从汇编中很难发现局部变量的长度,所以尽量将我们声明的变量地址空间多一些.

还有就是dll函数的清栈方式,要仔细观察反汇编的结果,看看它用的是哪种调用方式,这样才能保障栈平横,不至于缓冲区溢出.

发表在 C++ | 留下评论

给javascript引擎添加sleep函数.

js有sleep函数吗?,有,我们自已加.

如何在js中让函数睡眠多少秒? 经常会有Javascript初学者提出这样的问题,自从js出现以来.

即然该功能如此需要,但为什么js中不提供这样的函数呢?

目前浏览器都是在UI线程解析js,以火狐浏览器为例,我重新编译了js引擎,并且在js引警中添加了sleep方法,该方法调用c语言的线程睡眠函数.  

将方法附加到Object上,方法签名为sleep();无参数.默认休眠1秒钟,如果你在js中调用该函数,浏览器UI界面将被阻碍。

另外如果你的js函数存在死循环,浏览器的js解析会检测到js执行超时会提醒你是否终止执行本页面的js.

最后提供新编译的js引擎,将它们替换firefox下的js引擎即可.

然后你可以写一段js玩一玩,比如"testSleep".sleep();因为我是在Object添加的,所以你可以在任何js对象上调用这个函数.

附件:js.rar

发表在 JavaScript | 留下评论

你妈逼,中国联通

今天联通客服打电话到我家,说我家2010-06月份固定电话费未缴费,操 前些天刚交的… 回执单我都看过了46元
媳妇儿到营业厅还查不到底账,操你妈的联通,收我两次话费…
发表在 生活 | 留下评论

老年生活

今天上班的路上看到一位老人在路边 画画,当时我就一种美好的回忆,小时候的美好时光…
发表在 生活 | 留下评论

过生日罗

星期三
 
今天是阴历5月12日,我过生日,明天的阳历是6月24日也是我过生日,好多年才会碰到两个生日在一起的,这样也挺有意思的。
发表在 生活 | 留下评论

怀旧2 -电脑时代

作者:不及格的程序员-八神


在前一篇怀旧中(见怀旧 你是否还记得蜜桃精-纯真的80年代的),介绍了许多值得回忆的东西,这篇继续追忆过去的美好时光.

电脑是20世纪最最伟大的发明之一

实际上,在我中学快毕业时,就听到有人说要报考到职业高中里学习微机(微型计算机,不如个人电脑好听),当时还不知道它是什么东西,认为它就是一个比计算器大些的计算器.

直到1996,才在电脑游戏厅看到它真正的样子,孩子们用它在玩红色警界.

我太落后了,POWER键是开关都不知道.与此同时学校里开了微机课,操作系统是dos6,286cpu…

 

应该说个人电脑起源于施乐公司

下图为Xerox Alto,制造于1973.但它未产品化,直到1984年苹果公司仿造它制造出了更好的MAC电脑.

 

在没有个人电脑之前,人们都在是大型机/小型机上才能获得编程的乐趣.有一个天才小子斯蒂夫沃兹,由于它在父亲(在洛克马丁西德公司工作)的良好教育下,小时候就是一个发明家,以至于长大,很容易就能设计并造出个人电脑.

下图苹果II型电脑以及内部构造,它没有显示器,需要接到电视或投影仪上.

苹果电脑使用MOS科技公司(创始人来自于摩托罗拉)的微处理器6502,见下图

 

另一条主线,微软的产生.

Altair 8800(牛朗星)1974年面世,比尔盖茨与保罗艾伦因主动为它编写BASIC程序而出名.

这种机器也没有显示器,而且没有键盘,只有开关与指示灯,输出结果只有看哪些灯亮了

 

最后奉上一些珍贵老照片:

摩托罗拉公司的移动电话早期产品,大家应该在电影中已看到过多次了,比如二战,越战.

Intel 4004微处理器

苹果早期的智能手机
牛顿.

另外乔布斯很注重面子与名利.

乔布斯与比尔,后者是很历害的软件开发工程师,它开发了mac电脑上的图形编辑软件MacPaint,PhotoShop中常见的马蚁线效果就是它的发明.

MacPaint 软件的工具栏,微软的画图工具,Photoshop都是仿制品.

….

 


发表在 计算机与 Internet | 一条评论

怀旧

作者:不及格的程序员-八神

我是一个怀旧的人,喜欢回忆过去,记忆中的过去总是美好的

那时的天空总是很蓝.

小时候兜里根本没钱,有一毛两毛的就不错了,最便宜的小食品是汽水糖,一分钱一个.

还有一个叫蜜桃精的袋装糖品,现在已找不到它的样子.但是袋子里还有各式各样的小勺还是能找到的.

能吃上这种两色两味的小人雪糕,更是有钱人家的孩子能做的.

在小的时候一般都照过这样的"艺术照"

上学之后,小学课本,这一课大家都不会忘吧

在同学间流行的东西彩笔(我没有过,买不起),日记(女生写的比较多).

 

作为一个程序员,我要回忆的过去还包括:

格蕾丝·赫柏,它发现了第一只bug.

斯蒂夫·盖瑞·沃兹尼亚克,是它制造了苹果I,II型个人电脑,并且为它写了BASIC解释器.甚至蓝盒子与电视干扰器,它是个软硬全才.而乔布斯只能说是个滑头儿而已.(看来有点技术崇拜)

微软,先后与apple,ibm合作,树立了商业地位.bill gates 最聪明的小屁孩儿.

ABOBE公司,来自施乐的两个老头约翰与杰西卡.(施乐非常神奇,里面有许多高人,查尔斯-西蒙尼,恩格尔巴特,而且这里才是图形化电脑的发源地,乔布斯"偷"了它.)

公司创立时,乔布斯来参观,并谈谈合作的事情

 

还有IBM公司(通过收够成为真正的计算机公司),Intel公司(开始是卖内存条的),摩托罗拉(开始是做收音机的),仙童(里面的高人更多),康柏(依靠Intel386处理器的兼容机一路走红)…

发表在 生活 | 留下评论

儿子被落在幼儿园了

这两天下雨,就没有亲自送,由幼儿园的车接送,结果这第一次接送,儿子就被落在那儿了,孩它妈与车回去才接回来的 呵呵.

只剩儿子在幼儿园里的小板凳上坐着了。
发表在 宝宝日记 | 留下评论

“监视器(Monitor)与可靠性” -异步异常的影响

作者:不及格的程序员-八神

必备知识

   同步异常:指产生异常时,是我们预想到的,可以定义捕获的.

   异步异常:指代码中不可预料的异常,比如 ThreadAbortException、StackOverflowException 和 OutOfMemoryException 异常.   

   在CLR中的异步异常,有独特的异常码,例如 Access Violation异常码是 0xC0000005, divide by zero (integer)异常码是0xC0000094, divide by zero (floating)异常码是0xC000008E. 它们被CLR特别处理. 
   CLR中的同步异常就是指Throw抛出的异常对象,而它给RaiseException 的异常码为0xE0434F4D,这代表为托管异常.CLR会以SEH机制向系统注册异常处理函数来处理这些异常.

正文

   原子操作与异步异常:.NET下的异步异常 ThreadAbortException,通过另一个委托线程停止(调用Abort方法)当前线程时就会发生,它可以中断当前线程中正被执行的任何代码.

   这样就会产生问题,如果我们正在同步锁定一个对象,而又碰巧发生线程中止异常,那么被锁定对象将得不到释放。

  下面用简单的代码说明这种情况的发生,虽然几呼不可能.

 1 using System;
 2 namespace TempWebApplication1
 3 {
 4     public partial class Test : System.Web.UI.Page
 5     {
 6         private object sync = new object();
 7 
 8         protected void Page_Load(object sender, EventArgs e)
 9         {
10             //lock生成的代码与下面是相同的
11             System.Threading.Monitor.Enter(sync);
12             doSomething()//理论上这里不应该有代码,但是在调试模试下,JIT会生成NOP汇编指令,这样这里会可能会被ThreadAbortException中断(几率非常小,但是你要知道这个原理),而finally则不会执行.
13             try
14             {
15                 Response.Write("abc");
16             }
17             finally
18             {
19                 System.Threading.Monitor.Exit(sync);
20             }
21         }
22     }
23 } 

下面是调试版本的汇编节选,可以看到nop指令的.

System.Threading.Monitor.Enter(sync);
  mov         eax,dword ptr [ebp-3Ch] 
  
mov         ecx,dword ptr [eax+00000174h] 
  
call        726C216D 
  
nop              
try
{
  
nop              
Response.Write(
"abc");
  …

 

发表在 Asp .NET | 留下评论

.NET 应用程序域(AppDomain)并不可靠,微软的错误.

作者:不及格的程序员-八神

应用程序域,并不总是给应用程序带来隔离措失.

1 不可靠的CLR同步机制MethodImplOptions.Synchronized
        目前众所周知的在写线程同步代码时,不要锁定类型对象以及字符串常量.
2 应用程序域(AppDomain)同样的缺点:[LoaderOptimizationAttribute:LoaderOptimization.MultiDomain]
        这个属性被应用应用于进程的入口点方法(void Main),
        CLR支持的这种机制(共享列集:marshal-by-bleed,为了节省内存),可以将不同AppDomain中的引用指向内存中同一个CLR对象.

        这样的结果就是两个AppDomain域中的代码都可以在这个对象上执行锁定,而导至死锁,应用程序域将不具备应用程序隔离效应之说,而且你不能卸载AppDomain.
        这些对象可以是类对象(typeof(myClass)),字符串("abc"),原理同第1点所述.

这样的bug,在今后的clr版本中可能仍然存在,要考虑兼容性,如果被修复代价相当高.

发表在 Asp .NET | 留下评论