专栏首页逆向技术ShellCode之寻找Debug下真实函数地址

ShellCode之寻找Debug下真实函数地址

ShellCode之寻找Debug下真实函数地址

一丶简介与原理

​ 在Debug模式下,函数地址与真实函数地址不一致. 这导致我们在写类似于ShellCode的代码的时候会产生问题.比如远程线程代码注入.

产生这一原因是因为在Debug模式下,我们的函数地址是一层跳转表.是编译器维护的.名字叫做ILT,所以对函数名的直接访问都被映射了.映射为了修饰后的函数名.而真实函数地址在其跳转表之后.

如: JMP 偏移 JMP之后才是真正的函数地址.

在ILT表中的一般都是我们自定义的函数. 我们自定义的函数才会在其表中.

下面看一下代码与调试.

int fun1()
{
	int a = 10 * 10;
	scanf("%d", &a);
	return a;
}

int fun2()
{
	int b = 10 * 10;
	int c = b * 2;
	scanf("%d", &b);
	return c;
}
int main()
{
	fun1();
	fun2();
	printf("fun1 = %x \r\n",(DWORD)fun1);
	printf("fun2 = %x \r\n",(DWORD)fun2);
	/*printf("va fun1 %x \r\n", (DWORD)get_DebugVaAddress(fun1));
	printf("va fun2 %x \r\n", (DWORD)get_DebugVaAddress(fun2));*/
	system("pause");
	return 0;
}

可以看到定义了两个函数,分别是 fun1 以及 fun2 并且分别进行了调用. 下面我们就其调试看一下ILT表.

真实的函数地址

在调用fun1 函数之前我们进入了反汇编进行查看. 可以看到 现在的fun1地址其实是 0x00A3109B 而真实的fun1函数地址就是 0XA31750

这就会导致我们一个问题.当我们写ShellCode的时候.想要将fun1写入到内存中 一般都会进行如下几个步骤:

  • 1.定义fun1 并且在fun1中写好地址无关代码
  • 2.在fun1下面定义一个fun2函数.fun2可以什么都不做.或者加点标记
  • 3.利用 fun2 - fun1 得出 fun1函数的字节大小(ShellCode)大小
  • 4.利用写内存函数将fun1 写入到内存.

伪代码如下:

void fun1()
{
  //你的ShellCode代码
}
void fun2()
{
//做结束指令的fun2
   __asm{
     nop
     nop
   }
}
DWORD dwShellCodeSize = (DWORD)fun2 - (DWORD)fun1;
WriteProcessMemory(Process,BaseAdddr,fun1,dwShellCodeSize...);

如果程序运行在Release下是没有问题的.如果是Debug就会有问题了. 在Debug下函数都是ILT表. 两者相减就会出错.

而真实函数我们也知道是 ILT表中之后记录的函数地址. 也就是跳转之后的地址.

二丶原理与代码解决方式

在ILT表中记录的是 JMP + 偏移的方式 来进行跳转的. 而我们学过HOOK的伙伴们应该知道偏移是怎么的出来的.

偏移 = 目的地址 - 源地址 - 指令长度 而反过来说 目的地址 = 源地址 + 偏移 + 指令长度

比如上面的 伪函数fun1地址(0x00A3109B 记录的偏移为: 0x6B0) 真实fun1 0XA31750

代入指令:

  • 偏移 = 目的地址 - 源地址 - 指令长度 0XA31750 - 0x00A3109B - 5(jmp占5个字节指令长度) = 0x6B0
  • 目的地址 = 源地址 + 偏移 + 指令长度 0x00A3109B + 0x6B0 + 5 = 0XA31750

代码实现方式就很简单了.首先取出 伪函数地址. 对其按照 unsigned char * 类型解析. 判断首字节是否是E9(JMP)

如果是则取出后面的偏移,让当前地址 + 偏移 + 指令长度来得出真实地址.

注意因为你要判断16进制的0xE9 那么一定要按照UCHAR类型解析 否则高位会认为是符号位.

代码如下:

void* get_DebugVaAddress(void* procFunction)
{
    unsigned int VaAddr = 0;
    unsigned int VaOffset = 0;
    unsigned char* DebugCalcProc = NULL;
    if (procFunction == NULL)
    {
        return procFunction;
    }
    /*
    1.得出当前带有jmp跳转表的函数
        E9 XX XX XX XX
    2.判断是否是E9 如果是继续进行计算,不是返回自己函数本身
    3.是的情况下 从当前函数地址位置取出其偏移
      偏移在HOOK中是 目的地址 - 源地址 - 指令长度填写上的
      反过来讲 当前函数地址 + 指令长度 + 偏移则得到真实的目的地址
      计算真实地址即可。
    */
    unsigned int DebugVaAddr = (unsigned int)procFunction;
    DebugCalcProc = (unsigned char*)procFunction; //一定要uchar类型 要判断数值的
    if (DebugCalcProc[0] == 0xE9) //jmp
    {
        VaOffset = *(unsigned int*)(DebugCalcProc + 1);
        //当前地址 + 指令长度 + 偏移  = 目的地址
        VaAddr = DebugVaAddr + 5 + VaOffset;
        return (void*)VaAddr;
    }
    else
    {
        return (void*)procFunction;
    }
    return (void*)procFunction;
}

下面看下实战:

可以看出在Debug下我们自己进行转化可以得到真实函数地址. 这样在调试ShellCode的时候也更加方便.

当然如果你也可以加条件宏进行编译.这样Release下就不试用GetDebugVaAddress

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 小白详解rop emporium

    rop emporium网站上提供了许多构造rop的challenge,作为小白的我从这里开始,专注于rop链的构造。

    安恒网络空间安全讲武堂
  • 内核漏洞利用:通过WARBIRD在Windows 10上提升权限

    在这篇文章中,我想谈一谈通过基于Windows内核的exploit来提升权限。之所以没有使用像HackSys Extreme Vulnerable Window...

    FB客服
  • TP-LINK WR941N路由器研究

    是TP-Link WR940N后台的RCE, 手头上正好有一个TP-Link WR941N的设备,发现也存在相同的问题,但是CVE-2017-13772文章中给...

    Seebug漏洞平台
  • TP-LINK WR941N路由器研究

    作者:Hcamael@知道创宇404实验室 之前看到了一个CVE, CVE-2017-13772 是TP-Link WR940N后台的RCE, 手头上正好有一个...

    Seebug漏洞平台
  • 0Day技术分析-3-shellcode初探

    Shellcode初探 1 相关概念 这一章,我们介绍shellcode的相关概念,并对shellcode进行初步的探索,为我们后面的高级课程打下相关基础。 1...

    zhisheng
  • 通过POC来学习漏洞的原理

    本文介绍的是 easyFTPServer 1.7.0.2 ‘Http’ remote Buffer Overflow 的漏洞执行流程,通过已知的 POC 来推断...

    信安之路
  • Windows漏洞利用开发教程Part 5 :返回导向编程(ROP)

    本文主要介绍的是Windows软件漏洞的利用开发教程。我花了大量的时间来研究了计算机安全领域Windows漏洞利用开发,希望能和大家分享一下,能帮助到对这方面感...

    FB客服
  • nox&CSAW部分pwn题解

    暑假的时候遇到了一群一起学习安全的小伙伴,在他们的诱劝下,开始接触国外的CTF比赛,作为最菜的pwn选手就试着先打两场比赛试试水,结果发现国外比赛真有意思哎嘿。

    安恒网络空间安全讲武堂
  • nox&CSAW部分pwn题解

    暑假的时候遇到了一群一起学习安全的小伙伴,在他们的诱劝下,开始接触国外的CTF比赛,作为最菜的pwn选手就试着先打两场比赛试试水,结果发现国外比赛真有意思哎嘿。

    安恒网络空间安全讲武堂
  • 无文件执行:一切皆是shellcode (中)

    在上一篇文章中,介绍了PE_to_shellcode这个项目,并简单提了一句原理,本节就详细讲解一下PE是如何转化为shellcode的。

    七夜安全博客
  • Writeup丨国赛线上初赛解题最后一波~

    安恒网络空间安全讲武堂
  • 这样的Hello World好玩么

    春节之前我写过一个 Happy New Year 的文章,文章地址如下:用代码送上 Happy New Year,可能这样的代码对于很多程序员来...

    码农UP2U
  • 在TESLA MODEL S上实现MARVELL无线协议栈漏洞的利用

    在过去的两年里,腾讯科恩实验室对特斯拉汽车的安全性进行了深入的研究并在Black Hat 2017与Black Hat 2018安全会议上两次公开分享了我们的研...

    腾讯安全
  • Linux漏洞分析入门笔记-栈溢出

    1. 在进行远程调试之前需要对Linux平台进行一些准备工作。在IDA的安装目录中的dbgsrv文件夹中,选择linux_server或者linux_serve...

    我是小三
  • 二进制学习系列-栈溢出之Passcode详解

    概念:每一个外部定义的符号在全局偏移表(Global offset Table)中有相应的条目,GOT位于ELF的数据段中,叫做GOT段。

    安恒网络空间安全讲武堂
  • 安全视角下的木马免杀技术讨论

    实战演习中,攻击方需要通过各种手段对企业的相关资产进行渗透,挖掘企业资产里存在的漏洞进行得分。近年来这种漏洞挖掘的攻防比赛好像都以 Web 方面的为主,可能 W...

    FB客服
  • VC下提前注入进程的一些方法3——修改程序入口点

            前两节中介绍了通过远线程进行注入的方法。现在换一种方法——修改进程入口点。(转载请指明出处)

    方亮
  • 缓冲区溢出实战-slmail

    缓冲区溢出:当缓冲区边界限制不严格时,由于变量传入畸形数据或程序运行错误,导致缓冲区被填满从而覆盖了相邻内存区域的数据。可以修改内存数据,造成进程劫持,执行恶意...

    字节脉搏实验室
  • KeUserModeCallback用法详解(Ring0调用Ring3代码)

    ring0调用ring3早已不是什么新鲜事,除了APC,我们知道还有KeUserModeCallback.其原型如下: 代码:

    战神伽罗

扫码关注云+社区

领取腾讯云代金券