曲径通幽

programming_with_fun();

  C++博客 :: 首页 :: 联系 :: 聚合  :: 管理
  18 Posts :: 0 Stories :: 5 Comments :: 0 Trackbacks

常用链接

留言簿(6)

我参与的团队

搜索

  •  

最新评论

阅读排行榜

评论排行榜

这是从别人博客上摘的一段C嵌汇编码
( http://www.cppblog.com/kevinlynx/archive/2011/01/02/137886.html )
__declspec(naked)
void caller(void* pfn, 
{
    __asm 
    {
        pop eax;
        add eax, 3;
        xchg dword ptr[esp], eax;
        push eax;
        ret;
    }
}
下面是调用方法
void print_str( const char *s )
{
    printf( "%s\n", s );
}

{
   ...
caller( print_str, "a string" );
   __asm  add esp, 4
   ...
}

  原作者讲了一些基础,这里就不提了
看了一遍,发现 "ADD EAX, 3" 的用法有点奇怪(我相信搞破解的人一定比较熟悉,但正常的程序不会这么写。)
初看 EAX 是地址,+3是很危险的,但仔细一看,发现代码是为了从最外层主调函数一路穿越"caller" 直达 print_str,这里牵涉到一个重要问题,就是在CALL指令时,会有将“CALL指令下一条地址压栈”的操作,那么代码思路很明了了,就是为了要造出 调用print_str时,ESP(+0) 指向 caller(..)调用的下一个地址。
  第一关已经顺利搞定,但又碰到个问题,由于 print_str 的入参是可变的,所以必须用 cdecl调用,那RET之后 如何平栈呢? 如果直接跳到 caller下一条地址,就丧失了平栈的机会,最终会在某个主调函数上被微软的 stack cookie捕获抛个SEH。
  这里就用到文章开头提到的 ADD EAX, 3。
  必须要造一个环境,让 caller 调用完成后,给个机会清理现场。于是乎,caller之后就有了 ADD ESP, 4。其实这里的4是与print_str的入参数目相关的,每个参数要多加 4字节,如此一来,整个代码就理顺了。
  那为什么 是 ADD EAX, 3呢? 应该是预估出一条ADD指令占用多少长度,和具体的环境有关。因为没看INTEL手册,这里只能认为ADD 寄存器+WORD的长度是3个字节。我用VC试验了一下,的确是如此,我也尝试了ADD 寄存器+DWORD,长度变为了5个字节。
posted on 2011-01-06 12:48 Meiosis 阅读(453) 评论(0)  编辑 收藏 引用 所属分类: Windows GenericDebug \ Reverse Engineering

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理