Shellcode编程小技巧

工作需要,需要注入其他程序监控一些东西,检测到的数据通过WM_COPY 消息发送给显示窗体。(大体是这样的还没定稿)

##1 选择一个框架 ##

tombkeeper/Shellcode_Template_in_C

mattifestation/PIC_Bindshell

框架选择上,我选择了第一个,妇科圣手tomkeeper提供的框架,对比发现这个比较简单。

##2 搭建框架 ##

我使用的是vs10,(vs15我试了下各种错误 ,可能是自己笨吧,用管了vs10了)

- 新建个解决方案(名字看自己喜好)

- 解决方案上新添个空的 win32console 工程

- 再在工程上新建个 xxxx.c的文件,把tomkeeper工程中的shellcode.c的内容复制过来

- 编译试试吧

- 其他的2个工具文件代码,分别是生成字符串用的工具(str2intarr.c) 和 生成函数hash宏定义的 gethash.c (方法同上)

- 我自己定义了个字符串生成的增强版(如下,我这个是cpp文件,和上面的有所不同),根据 第2个参数 <a/w> 将字符串转为多字节字符串和宽字节字符串。

#include <Windows.h>

int _tmain(int argc, char* argv[])
{
    if (argc < 2)
    {
        printf("Use %s <a/w> <string> \n",argv[0]);
    }else
    {
        printf("DWORD str[] = {\n\t");

        if (argv[1][0] == ‘a‘)
        {
            int strLen = strlen(argv[2]);
            strLen = (strLen /4 +1)*4;
            int n = strLen /4 ;
            DWORD* pArry = (DWORD*)malloc(strLen);
            ZeroMemory(pArry,strLen);
            memcpy(pArry,argv[2],strlen(argv[2]));

            for (int i=0;i<n;i++ )
            {

                printf("0x%08x",*(pArry+i));
                if (i != n-1)
                {
                    printf(", ");
                }
                if (i && i%9 ==8)
                {
                    printf("\n\t");
                }
            }

        }else
        {
            int strLen = strlen(argv[2]);
            int nAlloc = strLen*2+4;
            DWORD* pWchar = (DWORD*)malloc(nAlloc);
            ZeroMemory(pWchar,nAlloc);
            MultiByteToWideChar(GetACP(),NULL,argv[2],strLen,(WCHAR*)pWchar,strLen);
            int n = (strLen/2+1);
            for (int i=0;i< n;i++)
            {
                printf("0x%08x",*(pWchar+i));
                if (i != n-1)
                {
                    printf(", ");
                }
                if (i && i%9 ==8)
                {
                    printf("\n\t");
                }
            }

        }
        printf("\n};");
        //getchar();
    }
    return 0;
}

##3 编译选项的设置  ##

编译选项的设置直接关系到shellcode大小的准确计算,代码的排列顺序,以及代码的精简程度,还有 GS。。。 是否被添加。

- 设置为release模式,我就不多说了,大家都会

- 去掉Gs 选项,如果不去掉shellcode()中会有gs检测函数的插入,这是我们不想要的。

- opt, 调试时我选择 disable, 发布时我使用 minsize (体积小些)。disable代码顺序是一样的就是多了不少int3 (cc)。

- linker 下的debuging :generate Debug info 我设置为YES。便于调试,对shellcode无影响

##4 测试shellcode的正确性 ##

tomkeeper的工程能将shellcode以c数组的形式输出出来,我增加了个函数可以将 shellcode dump到2进制文件中。

- 利用c数组, char shellcode[] = {0xb8,....}; __asm{ call shellcode} ,这样的话要注意将 工程的NX关闭(数据执行保护DEP) ,不会的自行补脑

- 第2种将 dump出的文件读入到申请的可读可写可执行的内存中,然后 __asm { call lpMem} .(我用的这种办法,不用每次进行复制黏贴,编译,执行)

##5 小技巧 (排错、编程 经验) ##

- 不要用 *1.02 这种浮点算法,会死在这种命令上,那个2B2040绝对会出错

000300B3 DF6D D8 FILD QWORD PTR SS:[EBP-28]
000300B6 DC0D 40202B00 FMUL QWORD PTR DS:[2B2040]
000300BC D97D D6 FSTCW WORD PTR SS:[EBP-2A]

- 如何在shellcode后面追加上 配置信息便于测试呢

shellcode会带着些配置信息很长见的。 一般这些都是后期用工具合并上去的。

对于我们调试每次都去追加修改太麻烦了。所以要用到 #define NAKED __declspec(naked) 和 __asm{ __emit 0xbb }

__emit 可以使数据以代码的形式写入到代码段,也就是shellcode中。记得和 DWORD str[] = {0xabcdef,0xbaddef..}这种技术分开。这样就实现了任意数据的存入

NAKED 进制优化:当我们使用minsize选项的时候,这些代码可能就被优化掉,我试过了,所以才用到了NAKED,注意函数必须有 参数,声明不用实现用。

最后:在永远不会调用到的地方调用下,要不编译器一定会给你省略掉

void  StoreConfigData(DWORD dwVoid);

NAKED void  StoreConfigData(DWORD dwVoid)
{ 

__asm{
__emit 0xff
__emit 0xfe
__emit 0xff

.}

- 函数重定位

我们的shellcode都是经过 call联系出来的,在调用的时候编译器已经算好了偏移,所以不存在重定位的问题,但是,向createthread这种将传入函数地址作为参数的函数就会出先这种问题;

解决的办法就是要动态计算地址。

//记得-8
DWORD GetEip()
{
    __asm{
        call get_eip
get_eip:
        pop eax
    }
}
void WINAPI AdjustFunction(struct ADJUSTFUNCTIONS* pFuns)
{
    DWORD dwGetEip;

    dwGetEip = GetEip();
    dwGetEip -= 8;    //计算得到 GetEip()函数在内存中的地址

    pFuns->lpThreadProc = (DWORD)dwGetEip+( (DWORD)ThreadProc- (DWORD)GetEip ); // 以GetEip()函数做参考动态计算出其他 函数的地址
}// 调用的时候这样写hThread = modules.kernel32.CreateThread(NULL,0,adjustFuns.lpThreadProc,&param,0,NULL);

ps:shellcode真省地方,写了这么多代码还没2K呢。

时间: 2025-01-14 15:16:11

Shellcode编程小技巧的相关文章

hadoop编程小技巧(4)---全局key排序类TotalOrderPartitioner

Hadoop代码测试版本:Hadoop2.4 原理:在进行MR程序之前对输入数据进行随机提取样本,把样本排序,然后在MR的中间过程Partition的时候使用这个样本排序的值进行分组数据,这样就可以达到全局排序的目的了. 难点:如果使用Hadoop提供的方法来实现全局排序,那么要求Mapper的输入.输出的key不变才可以,因为在源码InputSampler中提供的随机抽取的数据是输入数据最原始的key,如下代码(line:225): for (int i = 0; i < splitsToSa

积累的VC编程小技巧之对话框

1.用鼠标移动基于对话框的无标题栏程序的简单方法 void CVCTestDlg::OnLButtonDown(UINT nFlags, CPoint point) {    //一句话解决问题     SendMessage(WM_SYSCOMMAND,0xF012,0);    CDialog::OnLButtonDown(nFlags, point);} 2.对话框消息映射 有对话框A,B从A中发消息给B然后B处理.准备工作,先定义消息,如下#define WM_B_NOTIFY WM_U

积累的VC编程小技巧之工具提示

1.用鼠标移动基于对话框的无标题栏程序的简单方法 void CVCTestDlg::OnLButtonDown(UINT nFlags, CPoint point) {    //一句话解决问题     SendMessage(WM_SYSCOMMAND,0xF012,0);    CDialog::OnLButtonDown(nFlags, point);} 2.对话框消息映射 有对话框A,B从A中发消息给B然后B处理.准备工作,先定义消息,如下#define WM_B_NOTIFY WM_U

积累的VC编程小技巧之树操作

1.如何在TreeList中加图标? [问题提出]  请问treeview控件和treectrl控件的用法有何不同呢?向如何imagelist控件中加图象呀?  [解决方法]  1)    HICON hicon[8];    m_imageList.Create(16,16,0,8,8);    hicon[0]=AfxGetApp()->LoadIcon(IDI_ICON0);    hicon[1]=AfxGetApp()->LoadIcon(IDI_ICON1);    hicon[2

积累的VC编程小技巧之图标、光标及位图

1.图标透明 (1).Windows中的图标其实是有两个图像组成的,其中一个用于与它要显示的位置的图像做"AND"操作,另一个作"XOR"操作. 透明:用"白色"AND,用"黑色"XOR反色:用"白色"AND,用"白色"XOR正常色:用"黑色"AND,用正常颜色XOR.(2). WIN9X中好像是对像素的操作实现透明的WIN2K中就有API直接实现透明了!WIN2K中

积累的VC编程小技巧之框架窗口及其他

1.修改主窗口风格 AppWizard生成的应用程序框架的主窗口具有缺省的窗口风格,比如在窗口标题条中自动添加文档名.窗口是叠加型的.可改变窗口大小等.要修改窗口的缺省风格,需要重载CWnd::PreCreateWindow(CREATESTRUCT& cs)函数,并在其中修改CREATESTRUCT型参数cs.CWnd::PreCreateWindow 函数先于窗口创建函数执行.如果该函数被重载,则窗口创建函数将使用CWnd::PreCreateWindow 函数返回的CREATESTRUCT

积累的VC编程小技巧之文件操作

1.删除文件夹 // 删除文件夹及其所有内容void CBaseDoc::RemoveFolder(const CString &strPathName){    CString path = strPathName;    if (path.Right(1) != _T("\\"))        path += _T("\\");    path += _T("*.*");    CFileFind ff;    BOOL res =

积累的VC编程小技巧之组合框

1.如何正确的得到ComBox的指针 CComboBox *mComb = (CComboBox*)GetDlgItem(IDC_DuanCB); CComboBox *mComb = (CComboBox*)::GetDlgItem(m_hWnd,IDC_DuanCB); 2.CComboBox控件详解 CComboBox控件又称作组合框控件,其有三种形态可供选择,1.简单组合框(Simple)2.下拉组合框(Drop-down)3.下拉列表式组合框(Drop-down list). CCom

积累的VC编程小技巧之列表框

1.列表框中标题栏(Column)的添加 创建一个List Control,其ID为IDC_LIST,在其Styles属性项下的View项里选择Report.Align项里选择Top.Sort项里选择None. 然后在该List所在对话框的类(头文件)里创建ClistCtrl的一个对象m_list然后在.cpp文件的OnInitDialog()之类的函数里实现如下代码: CString strname[3]; strname[0]="Screen Name"; strname[1]=&