首页
社区
课程
招聘
[旧帖] [求助]看雪坛子的大虾来 小虾就别来了 0.00雪花
发表于: 2010-3-2 10:48 1920

[旧帖] [求助]看雪坛子的大虾来 小虾就别来了 0.00雪花

2010-3-2 10:48
1920
#include "stdio.h"

void __cdecl test(){
	__asm{
		add esp,12
	}
	printf("hallo");
}


int __cdecl main(int __argc,char** __argv, char** __environ){
	
	__asm{
		mov eax,401000h
		push eax
		push ebp
		push ebx
		push esi
		push edi
	}
	
	return 0;
}


mov eax,401000h是硬编码的  是test函数的地址

怎样获取在内连汇编里获取c函数的地址  我用 mov eax,offset test 不行   用mov eax, test就不是传送test地址了 而是test地址中的值。

内连汇编获取c函数地址已经解决 谢谢2楼mm

另外 怎样从test函数中再直接返回mainCRTstartup函数执行exit正常退出   现在程序会崩溃 期待看雪大虾出来解释下

[课程]FART 脱壳王!加量不加价!FART作者讲授!

收藏
免费 0
支持
分享
最新回复 (19)
雪    币: 2687
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
获取test函数的地址“mov eax,offset test”可以的啊。还可以用“lea eax,dword ptr test”。
但是你的“__asm{    add esp,12  }“使堆栈不平衡,导致程序崩溃。内嵌汇编要注意函数调用时参数入栈和堆栈平衡。
2010-3-2 11:06
0
雪    币: 13
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
@2
噢。。

我看错了 mov eax,offset test是个warning 不是error

另外 我的add esp,12  是使堆栈平衡  因为ret指令使eip直接跳到了test函数入口处  __cdecl需要主调函数平衡堆栈  但是直接跳到了test函数入口处了 所以没能平衡堆栈  所以我家了 add esp,12 自己手动平衡了堆栈

程序崩溃另有原因  要怎么才能正常返回的mainCRTstartup函数执行exit  这个要等看雪的大虾出来解释了。。
2010-3-2 11:22
0
雪    币: 2687
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
你还挺固执的。不信你自己调试一下就知道了。你根本就没调用test函数体,你平衡什么堆栈?平衡main函数体内的堆栈你只用pop就可以了。
2010-3-2 11:43
0
雪    币: 26
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
两位mm莫要吵架 莫要吵架  虽然没有调用test函数  但楼主mm的代码里依靠修改堆栈使ret返回到了test的入口处    test函数里的add esp,12  是想平衡main函数的堆栈吧?

不过楼主mm忘记了一个问题  ret指令使你直接跳到test函数的入口点了  main函数里面你曾经push ebx push edi push esi  这些都没平衡。。
2010-3-2 11:48
0
雪    币: 15
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
小虾路过围观

话说我点进来才知道这贴不欢迎我这个虾米。。
2010-3-2 13:11
0
雪    币: 13
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
刚才经调试 问题已解决 谢谢memspirit的提醒 不过我不是想平衡main函数的堆栈  只要能返回mainCRTStartup  那就让mainCRTStartup去平衡调用main函数的堆栈  我add esp,12  漏掉一个相应的push  应该是add esp,16 这样栈顶就是返回mainCRTStartup的地址了  

问题已解决 完整代码和注释在下面 大家编译后调试一下  注意栈的变化 一看便知  

#include "stdio.h"

void __cdecl test(){
  __asm{
    add esp,16 //恢复main函数入口处C编译器自动生成的 ebp ebx esi edi 寄存器所占堆栈
  }
  printf("hallo");
  
  //因为从来没有调过test 而是从main函数ret到test函数的入口处的  所以这时候栈顶是返回到mainCRTStartup
}


int __cdecl main(int __argc,char** __argv, char** __environ){
  
  //函数入口处C编译器将自动生成代码用来保护 ebp ebx esi edi四个寄存器
  // push ebp
  // mov ebp,esp
  // push ebx
  // push esi
  // push edi
  
  
  __asm{
    mov eax,offset test
    push eax		//ret指令将使用这个地址跳转
    
    push ebp		//实际上这里有个错误  这个ebp已经被修改过了
    push ebx
    push esi
    push edi
  }
  

  return 0;	//xor eax, eax

  //函数末尾处C编译器也将自动生成代码用来恢复 edi esi ebx ebp四个寄存器
  // pop edi
  // pop esi
  // pop ebx
  // pop ebp		
  
}
2010-3-2 13:21
0
雪    币: 458
活跃值: (421)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
8
看不懂你们的代码 不过我写了一个   Release版本不崩溃 且能打印出来 Hello的代码

#include "stdafx.h"
#include "stdio.h"

void __cdecl test()
{
	printf("hello \n"); 
}

int __cdecl main(int __argc,char** __argv, char** __environ){
  
  __asm
  {
    mov eax,offset test
    push eax
  }
} 
2010-3-2 13:43
0
雪    币: 13
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
push ebp
mov ebp, esp
push ebx
push esi
push edi

__asm{
  mov eax, offset test
  push eax
}

pop edi
pop esi
pop ebx
pop ebp

楼上你的c编译器没有生成保护ebx esi edi的代码么  即使没有 那ebp总该有的吧  你仅仅是一个push offset test,接下来会立即pop ebp  这时候ret就会用原始ebp中的值做返回地址了。。
2010-3-2 13:48
0
雪    币: 458
活跃值: (421)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
10
我用的是VC6.0的编译器   这种代码跟编译器有莫大的关系  研究这些东西不如  仔细读读汇编书   反正我的代码在Release版本下是没有问题的  
解释也相当简单
->   mov eax,offset test  执行到这句的时候堆栈里面存的数据是main的返回地址 应该是内核级或者一些系统dll里
->     push eax 把test函数的地址入栈
->   ret        这句是隐藏的  反汇编才能看到
ps. return 0则不是这种情况  会加一个 xor eax,eax 的操作

这时候就从main来到了 test函数 执行完了一个 printf后  
要执行ret  而此时 堆栈里只剩下原本main要返回的地址(另一个被main的ret '吃掉'了)  所以就能很完美的衔接好    不会崩溃

ps.做这样的练习 要用OD来配合比较好
2010-3-2 13:56
0
雪    币: 2687
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
不同的编译器下生成的代码不同。讨论这些没有意义。重要的是学到知识。
2010-3-2 15:11
0
雪    币: 401
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
哈哈,这个也有取巧的成分,debug版本下VC编译器会添加
cmp esp,ebp
call _chkesp
来检查ebp和esp是否相等,release版本下没检查……esp明显比ebp小4,呵呵。
2010-3-3 08:54
0
雪    币: 458
活跃值: (421)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
13
[QUOTE=xiilin;769437]哈哈,这个也有取巧的成分,debug版本下VC编译器会添加
cmp esp,ebp
call _chkesp
来检查ebp和esp是否相等,release版本下没检查……esp明显比ebp小4,呵呵。[/QUOTE]

说要说嘛    11楼说的很对   讨论这些没什么意义     
我认为所有的问题都可以放到OD下反汇编一下    就都一目了然了    都汇编知识  没啥意义
2010-3-3 09:04
0
雪    币: 401
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
事实上根本不必关心那些push ebx,push esi,push edi之类的指令,只记住一点:进入函数后第一句是push ebp,想从test()返回到mainCRTstartup就很简单了,在test()内当前ebp指向的栈单元内存放的是main()内的ebp值,而main()内的ebp+4指向的栈单元内存放的就是mainCRTstartup的返回地址,所以可以这样写:
#include <stdio.h>
 
void _cdecl test()
{
printf("Hello\n");
_asm
{
mov eax,[ebp] //取出main()内的ebp值
mov eax,[eax+4] //取出mainCRTstartup的返回地址
jmp eax //直接跳过去
}
}
 
int _cdecl main(int _argc,char **_argv,char **_env)
{
test();
return 0; //这一句执行不到了
}
2010-3-3 09:47
0
雪    币: 458
活跃值: (421)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
15
[QUOTE=xiilin;769475]事实上根本不必关心那些push ebx,push esi,push edi之类的指令,只记住一点:进入函数后第一句是push ebp,想从test()返回到mainCRTstartup就很简单了,在test()内当前ebp指向的栈单元内存放的是main()内的ebp值,而main()内的ebp+4指...[/QUOTE]

你要我们记住的这点好像是错的
#include "stdafx.h"

void test(void)
{
	printf("Hi!\n");
}
int main(int argc, char* argv[])
{
	test();
	return 0;
}


反汇编后的代码
00401000  /$  68 30704000   push    00407030                         ;  ASCII "Hi!",LF
00401005  |.  E8 16000000   call    00401020
0040100A  |.  59            pop     ecx
0040100B  \.  C3            retn
0040100C      90            nop
0040100D      90            nop
0040100E      90            nop
0040100F      90            nop
00401010  /$  E8 EBFFFFFF   call    00401000
00401015  |.  33C0          xor     eax, eax
00401017  \.  C3            retn
00401018      90            nop
2010-3-3 10:17
0
雪    币: 401
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
[QUOTE=blueapplez;769494]你要我们记住的这点好像是错的
#include "stdafx.h"

void test(void)
{
    printf("Hi!\n");
}
int main(int argc, char* argv[])
{
    test();
    return 0;
}

反汇编...[/QUOTE]

汗,你是用的哪个版本的VC?我在VC6下编译看了一下,debug和release版本都有push ebp,mov ebp,esp这两句
2010-3-3 10:45
0
雪    币: 401
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
这种方法能不能跳过上一层函数,只要写段代码试一下就知道了
#include <stdio.h>
 
void test2()
{
printf("test2\n");
_asm
{
mov eax,[ebp]
mov eax,[eax+4]
jmp eax
}
}
 
void test1()
{
test2();
printf("test1\n");
}
 
int main(int argc,char *argv[])
{
test1();
printf("main\n");
return 0;
}


把这个拿去编译运行一下,可以看到输出是"test2"和"main",没有输出"test1",因为内嵌的那段汇编跳过了test1,直接返回到了main函数里。

ps:用release模式编译,为了简短,只偷了ebp的值来获得main函数的返回地址,没有去偷esp的值,所以debug模式下执行call _chkesp时会出现一个断言错误。
2010-3-3 10:53
0
雪    币: 458
活跃值: (421)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
18
Microsoft Visual C++ 6.0(SP6)   这下清楚了吧
2010-3-3 12:01
0
雪    币: 401
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
那应该没问题啊,我也是这个版本,记得VC的有个编译优化选项是可以关闭用ebp访问局部变量的,关闭了那个选项就会全都用esp访问,如果是那样的话,可以用最右边的参数的地址+4来取得上一个函数的返回地址:-)
或者你编译一下我的17L发的那段代码试一下。
2010-3-3 12:13
0
雪    币: 6772
活跃值: (3689)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
很精彩...
2010-3-3 13:29
0
游客
登录 | 注册 方可回帖
返回
//