网络通信 频道

windows下生成shell的一种新方法(2)

面是shell数据的初始化与shell的输出。shell中数据段是如何定位的。大家看看不被执行的那一段汇编程序,mov ebp,esp,使ebp指向shell的代码段(运行时)开始处。add ebp,0x11111111,使ebp的指针下移(0x11111111并不是最终值,这个0x11111111会前面的shell[4+i]=?处中被off覆盖,4是0x11111111在shell中的偏移量),指向数据段(运行时)起始处。这下好了前面写入data[x]中的数据,我们可以在shell中用[ebp+x]来访问(也就是说shell与data形成了一一应的关系)。这里直接用off覆盖可能会产生0,我们可以把off与0xffffffff进行异或再覆盖,当然在shell中也要异或一次。最后我们把上面的程序稍作改动,并定义成宏。并把一些常用的操作也定义成宏,如下:

/*********shell.h*************/
/***程序框架的宏************/
#define SHELLDATA \
void main()\
{\
char *BUFF,*DATA,SHELL[50000];\
int CODESIZE,DATASIZE=0;\
int I;\
__asm mov eax,offset begin\
__asm mov BUFF,eax\
__asm mov CODESIZE,offset end\
__asm {sub CODESIZE,eax }\
for(I=0;I<CODESIZE;I++)\
SHELL=BUFF;\
for(I=0;I<4;I++)\
{ char ch=(char)(CODESIZE>>(8*I));\
SHELL[7+I]=(char)0xff-ch;\
}\
DATA=SHELL+CODESIZE;


#define SHELLCODE\
return;\
begin:\
__asm mov ebp,0xffffffff\
__asm xor ebp,0x11111111\
__asm add ebp,esp


#define SHELLEND\
end:\
;\
}


/***赋值用的宏************/
#define STRING(ID,STR)\
strncpy(&DATA[ID],STR,strlen(STR)+1);\
if(DATASIZE<ID+(int)strlen(STR)+1)\
DATASIZE=ID+(int)strlen(STR)+1;


#define CHAR(ID,VAULE)\
DATA[ID]=VAULE;\
if(DATASIZE<ID+1)\
DATASIZE=ID+1;


#define INT(ID,VAULE)\
for(I=0;I<4;I++)\
{ char ch=(char)(VAULE>>(8*I));\
DATA[ID+I]=(char)ch;\
}\
if(DATASIZE<ID+4)\
DATASIZE=ID+4;

/***为使写SHELL方便,而定义的一些宏***********/

#define D(x) [ebp+x]
#define P(x) push x
#define L(x) }__asm lea edx,x __asm {push edx

#define INVOKE0(f) {call dword ptr f}
#define INVOKE1(f,p1) {p1}{call dword ptr f}
#define INVOKE2(f,p1,p2) {p2}{p1}{call dword ptr f}
#define INVOKE3(f,p1,p2,p3) {p3}{p2}{p1}{call dword ptr f}
#define INVOKE4(f,p1,p2,p3,p4) {p4}{p3}{p2}{p1}{call dword ptr f}

/***函数**********************/
void OUTPUT(char *shell,int num)
{
FILE *fp;
fp=fopen("shell","w");

//Hex输出
//fwrite(shell,num,1,fp);

//数组形式输出
for(int i=0;i<num;i++)
{fprintf(fp,"0x%x,",(unsigned char)shell);
if((i+1)%10==0)
fprintf(fp,"\n");
}

fclose(fp);
}

这里的SHELLDATA等是原来的程序主框架,是必须的;CHAR、STRING等宏是为了初始化数据时方便而写的的,第一个参数是一个整数,指明该参数在数据段中的位置。INVOKE4(f,p1,p2,p3,p4)中的4指的是函数中参数的个数是4个,f指的是函数名的地址如:可为[ebp+4],p1,p2是参数必须用L(地址入栈),P(直接入栈)来调用。例如:MessageBox函数的入口地址在[ebp+4]中,正文在[ebp+8]中,标题在[ebp+24]中,那么可写为
xor eax,eax
INVOKE4([ebp+4],P(eax),L([ebp+8]),L([ebp+24]),P(eax) )

到此,我们的程序就应该成如下格式:
#include <stdio.h>
#include <windows.h>
#include <stddef.h>
#include "shell.h"
SHELLDATA
//定义数据
STRING(0,"abcdefg")
INT(8,25)
CHAR(12,''A'')
……
//输出shell
OUTPUT(SHELL, CODESIZE+DATASIZE);
SHELLCODE
__asm{
//shell汇编代码
...
}
SHELLEND

接下来就是要找函数的API地址了,我们可以的LoadLibrary和GetProcAddress的入中地址放在DATA[0],DATA[4]中,以后可以直接使用call [ebp],call [ebp+4](CALL [ebp]会出现0,可用mov eax,ebp,call[eax]代替)。

要找地址的函数名放在DATA数组中,可从DATA[8]开始。函数名在找到地址后就没有用了,就把找到的地址放在函数名的位置(把函数名覆盖),这样有一个好处:可以直接根据函数名的位置访问函数。
数据段中的0要进行处理,我们可以在数据初始化之后,输出之前进行加密(用C在程序中实现),在SHELL的开头进行解密。这样得到的SHELL中的字符是加过密的,运行时自动解密,不要再另行处理了,十分方便。

由于本人对VC及宏不太了解,上面的一些代码并不合理,如INVOKE能不能用一个宏来写,数据初始时能不能自动定位,这些都有待广大读者来解决。

文章转载地址:http://www.cnpaf.net/Class/hack/05121820345084067994.htm

0
相关文章