首页
论坛
课程
招聘
[原创]利用传值API修改返回地址到指定代码处执行
2011-6-28 10:42 9736

[原创]利用传值API修改返回地址到指定代码处执行

2011-6-28 10:42
9736
刚在看一个拥有传值的API时(什么是传值?就是API参数有__out属性的),想到这么一个猥琐的方法,也真的实现了,觉得蛮新奇蛮好玩的,分享给大家,代码如下:
.386
.model flat, stdcall
option casemap :none

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include        windows.inc
include        user32.inc
includelib    user32.lib
include        kernel32.inc
includelib    kernel32.lib
.data
fmt    db "%s",0
msgtxt db "我怎么被执行了?",0
.code
New_OEP:
invoke MessageBox,0,addr msgtxt,0,0
invoke ExitProcess,0
start proc
local @temp
mov    @temp,New_OEP
lea    ecx,[esp-3*4-4]
invoke wsprintf,ecx,addr fmt,addr @temp

start endp
end start
当你执行wsprintf之后,代码并没有去执行下一条语句,而是去执行了上面的信息框,嘿嘿~~这里我用wsprintf是因为它的返回值比较容易控制,但必须要注意的是,因为wsprintf输出的是字符串,所以它输出的最后一个值必定是00,所以你需要一个地址是00结尾的新返回地址,当然你也可以自己找个容易控制的傀儡API,哈哈,,就到这了....如果你感兴趣,马上找到一个属于自己的傀儡API,把代码Show上来~~~大家分享分享!!

PS(以下内容均为之后添加):中间有个小错误,就是mov  @temp,New_OEP 新地址被存放里,因为数值是倒过来存放的,所以例子中的00401000在内存中是00 10 40 00 存放的,首字节变成了0,wsprintf 只会覆盖一个0到返回地址,正确的方式应该是在"New_OEP:"前面加上一句nop,使最地位地址不为0!


注意,请不要把这个代码当成是溢出利用,完全是两回事!!

C++版:
#include <Windows.h>
__declspec(naked) void test()
{
    MessageBoxA(0,"为什么我被执行了?",0,0);
}

int main()
{

    LPSTR outb;
    DWORD    addr = (DWORD)(LPDWORD)test;
    __asm{
        lea  ecx,[esp-3*4-4]
        mov    outb,ecx
    }
    wsprintfA(outb,"%s",&addr);
    return 0;
}
如果你还是认为这是溢出代码,请看这个:
#include <Windows.h>
__declspec(naked) void test()
{
    MessageBoxA(0,"为什么我被执行了?",0,0);
}

int main()
{

    LPSTR retaddr;
    DWORD    addr = (DWORD)(LPDWORD)test;
    __asm{
        lea  ecx,[esp-4*4-4]
        mov    retaddr,ecx
    }
    strncpy_s(retaddr,4,(char *)&addr,4);//这个不会溢出了吧~
    return 0;
}

看雪2022 KCTF 秋季赛 防守篇规则,征题截止日期11月12日!(iPhone 14等你拿!)

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (18)
雪    币: 527
活跃值: 活跃值 (86)
能力值: ( LV12,RANK:360 )
在线值:
发帖
回帖
粉丝
Mx¢Xgt 活跃值 7 2011-6-28 11:22
2
0

.code
New_OEP:
invoke MessageBox,0,addr msgtxt,0,0
jmp _Retn-3
start proc
local @temp
mov	@temp,New_OEP
lea	ecx,[esp-3*4-4]
invoke wsprintf,ecx,addr fmt,addr @temp
_Retn::
ret
start endp



如果你改这样,wsprintf执行能返回,这样,调试都根本想不到中间执行了什么,不过我因为我中间执行的是一个信息框,所以才会被你发现~
上传的附件:
雪    币: 143
活跃值: 活跃值 (10)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
五边形 活跃值 1 2011-6-28 12:52
3
0
LZ真恶搞,主要是修改函数调用的Ret地址跳转到指定地址执行,要是这样那方法应该也会超多的。
也画个瓢
void __cdecl MyTest(int a, int b, int c)
{
    printf("This is my test!\r\n");
}

int _tmain(int argc, _TCHAR* argv[])
{    
    DWORD dwAddr = (DWORD)(LPDWORD)MyTest;
    LPDWORD lpMemcpyRetAddr = NULL;
    _asm
    {
        xor eax, eax
        lea eax, [esp - 3*4 - 4]  //3*4是3个参数占的栈空间 -4 是返回地址的栈空间
        mov lpMemcpyRetAddr , eax  //保存memcpy返回的地址,也就是memcpy后面第一条汇编执行地址
    }
    memcpy(lpMemcpyRetAddr , &dwAddr, sizeof(DWORD));


不过返回时程序流程就被修改了,要是能再顺序执行就会比较h了。
雪    币: 527
活跃值: 活跃值 (86)
能力值: ( LV12,RANK:360 )
在线值:
发帖
回帖
粉丝
Mx¢Xgt 活跃值 7 2011-6-28 15:45
4
0
终于有个认真看的了,不错..我后面补充的那个方法,就是执行完我自己的代码后,继续回到原来的位置..当然这是在MASM里面实现的
雪    币: 0
活跃值: 活跃值 (24)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
tihty 活跃值 2 2011-6-28 16:15
5
0
学习了 :)
雪    币: 583
活跃值: 活跃值 (155)
能力值: ( LV11,RANK:190 )
在线值:
发帖
回帖
粉丝
RootSuLe 活跃值 4 2011-6-28 16:19
6
0
膜拜,其实我看不懂
雪    币: 160
活跃值: 活跃值 (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hackboylyq 活跃值 2011-6-28 18:46
7
0
收藏下,哈哈
雪    币: 143
活跃值: 活跃值 (10)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
五边形 活跃值 1 2011-6-28 20:05
8
0
返回地址补充下,不过感觉怪怪的。

DWORD g_dwRetEip = 0;

__declspec(naked) void __stdcall MyTest(int a, int b, int c = 3*4)
{
    DWORD dwWrite;
    printf("This is my test!\r\n");
    _asm
    {
        lea eax, [esp + 2*4 ]   //地址具体见图
        mov dwWrite, eax
    }
    WriteProcessMemory(GetCurrentProcess(), (DWORD*)dwWrite, &g_dwRetEip, sizeof(DWORD), &dwWrite);    
    _asm
    {
        lea esp, [esp + 2*4]   //地址具体见图
        ret                 
    }
}

int _tmain(int argc, _TCHAR* argv[])
{   
    _asm
    {
        call HOUHOU
HOUHOU:
        pop eax
        sub eax, HOUHOU
        add eax, RET_HERE
        mov g_dwRetEip, eax
    }
    DWORD dwAddr = (DWORD)(LPDWORD)MyTest;
    LPDWORD myRet = NULL;
    _asm
    {
        xor eax, eax
        lea eax, [esp - 3*4 - 4]   //地址具体见图
        mov myRet, eax
    }
    memcpy(myRet, &dwAddr, sizeof(DWORD));

RET_HERE:    
    printf("just test!\r\n");

上传的附件:
雪    币: 84
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xnop 活跃值 2011-6-29 05:59
9
0
果然灰常有创意.有意思啊
雪    币: 1
活跃值: 活跃值 (408)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
网络游侠 活跃值 2011-6-29 08:56
10
0
看了楼主的帖子,得到一个新启发,可以依靠修改函数的返回地址构造自己的shellcode进行干坏事!
雪    币: 258
活跃值: 活跃值 (11)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
AZMC 活跃值 6 2011-6-29 09:50
11
0
不错哦!
雪    币: 423
活跃值: 活跃值 (396)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
starrysky 活跃值 2011-6-29 10:43
12
0
本质就是format string 漏洞的利用方式
雪    币: 1078
活跃值: 活跃值 (570)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
loqich 活跃值 2011-6-29 11:17
13
0
我也来贴一个类似的...

#pragma optimize("", off)

DWORD g_dwRetEip = 0;
__declspec(naked) void MyTest()
{
printf("This is %s\n", __FUNCTION__);
__asm
{
jmp g_dwRetEip
}
}

void Test(DWORD dwV) // 必须存在一个以上参数用来获取返回地址
{
PDWORD pdwEsp = &dwV;
g_dwRetEip = *(pdwEsp - 1);
*(pdwEsp - 1) = (DWORD)MyTest;
}

#pragma optimize("", on)

int _tmain(int argc, _TCHAR* argv[])
{
Test(0);
return 0;
}
雪    币: 143
活跃值: 活跃值 (10)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
五边形 活跃值 1 2011-6-29 12:18
14
0
LS的用参数来获取Ret地址比较通用,
你们都太会玩了,玩的也太邪恶了
看来是我太单纯
雪    币: 527
活跃值: 活跃值 (86)
能力值: ( LV12,RANK:360 )
在线值:
发帖
回帖
粉丝
Mx¢Xgt 活跃值 7 2011-6-29 14:35
15
0
不知道你指的是不是溢出?
雪    币: 68
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
sunnywwc 活跃值 2011-6-30 02:29
16
0
还真挺有意思的~哈哈
雪    币: 317
活跃值: 活跃值 (15)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
comealong 活跃值 2011-6-30 10:25
17
0
你必须有预先修改目标地址和源地址机会, 这和溢出原理是一样的, 可利用的地方基本没有
雪    币: 325
活跃值: 活跃值 (20)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
morning 活跃值 1 2011-11-23 12:02
18
0
编译开启 /GS,修改返回地址还能这么玩么?
雪    币: 39
活跃值: 活跃值 (478)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
iceway 活跃值 2011-11-23 12:35
19
0
可以干坏事!
游客
登录 | 注册 方可回帖
返回