將數據放入代碼中的shellcode函數
06-06
有的時候我們需要用shellcode執行一個函數,這個函數中包含一些全局的數據,你會怎麼做
(1)這個函數的代碼將從0地址開始執行
(2)如何能夠找到與0地址相對的偏移地址
解決方案:
(1)方法1:0地址處使用push指令將數據壓入棧中,形成棧變數:這種方法適用小量的局部數據,因為大量的數據產生較多指令
(2)方法2:push , call , pop 方法
fun:
push edi ;徵用edi寄存器
call entry ;跳轉到entry,此時eip入棧(受取指流水線影響,此時的edi正好是data1的值)
data1:
......
entry:
pop edi ;彈出eip到edi,此時edi=data1
mov eax edi ;交給eax
pop edi ;釋放對edi的徵用
(3)方法2理論上通過的,但實際用C語言怎樣編寫這樣代碼呢?
[cpp] view plain copy
- #include"stdafx.h"
- #include<Windows.h>
- BOOL__stdcallMyStrEqu(char*user,char*data);/////////////////////////////注意這個聲明,可能導致函數地址排布出現混亂,如沒有則未優化的時候static函數都是相對模塊線性增序
- staticBOOL__declspec(naked)CheckUserAndPass2(char*user,char*passwd)///為防止編譯器插入其他espbuffer檢測代碼,函數直接用naked的
- {
- __asm
- {
- pushebp;////naked的約定下,要仿造cdecl對頁指針保護
- movebp,esp;
- //paraebp+4ebp+8
- //下面開始我們的shellcode
[cpp] view plain copy
- pushebx;//需要徵用ebx作為一個臨時指針
- pushedi;
- callentry1;
- _emit"a";//_emit等價db(數據可以用其他程序生成_emit形式的代碼~~)
- _emit"a";
- _emit"a";
- _emit0;
- entry1:
- popedi;
- movebx,edi;
- popedi;
- pushebx;
- pushdwordptr[user];
- callMyStrEqu;
- cmpeax,0;
- jzret0;
- pushedi;
- callentry2;
- _emit"b";
- _emit"b";
- _emit"b";
- _emit"x";
- _emit"x";
- _emit0;
- entry2:
- popedi;
- movebx,edi;
- popedi;
- pushebx;
- pushdwordptr[passwd];
- callMyStrEqu;
- cmpeax,0;
- jzret0;
- popebx;
- moveax,1;//返回1
- popebp;
- ret;
- ret0:
- popebx;
- moveax,0;<spanstyle="font-family:Arial,Helvetica,sans-serif;">//返回0</span>
- popebp;
- ret;
- };
- }
- staticBOOL__stdcallMyStrEqu(char*user,char*data)
- {
- if(!user||!data)
- returnFALSE;
- while((*user)&&(*data)&&((*user)==(*data)))
- {
- user++;
- data++;
- }
- return(*user)==(*data);
- }
- staticvoid__empty(){};//__empty必須在代碼中出現,否則很容易被優化掉導致計算代碼距離失敗
- BOOLCheckUserAndPass(char*user,char*passwd)
- {
- if(MyStrEqu(user,"aaa")&&MyStrEqu(passwd,"bbbxx"))
- {
- returnTRUE;
- }
- returnFALSE;
- }
- int_tmain(intargc,_TCHAR*argv[])
- {
- charbf_user[100]={};
- charbf_pass[100]={};
- printf("testCheckUserAndPass:
inputUser:"); - gets(bf_user);
- printf("inputPass:");
- gets(bf_pass);
- printf("result:%d
",CheckUserAndPass(bf_user,bf_pass)); - //////////////////////////////////////////////////////////////////////////
- printf("testCheckUserAndPass2:
inputUser:"); - gets(bf_user);
- printf("inputPass:");
- gets(bf_pass);
- printf("result:%d
",CheckUserAndPass2(bf_user,bf_pass)); - //////////////////////////////////////////////////////////////////////////編譯器可能最終會優化函數順序導致我們需要的兩個函數位置發生調換,用演算法尋找最上面的start
- unsignedintfs_empty=((unsignedint)(void*)__empty);
- unsignedintfs_addf=((unsignedint)(void*)MyStrEqu);
- unsignedintfs_addf2=((unsignedint)(void*)CheckUserAndPass2);
- unsignedintfunc_entry=((unsignedint)(void*)CheckUserAndPass2);//入口地址
- unsignedintfstart=fs_addf<fs_addf2?fs_addf:fs_addf2;
- unsignedchar*buf=newunsignedchar[abs(fs_empty-fstart)+100];
- if(fstart<=fs_empty)
- for(unsignedinti=0;i<(fs_empty-fstart);i++)
- {
- unsignedcharby=((unsignedchar*)fstart)[i];
- buf[i+5]=by;//要在前面插入shortjmp
- }
- else
- for(unsignedinti=0;i<(fstart-fs_empty);i++)
- {
- unsignedcharby=((unsignedchar*)fstart)[i];
- buf[i+5]=by;
- }
[cpp] view plain copy
- <spanstyle="white-space:pre"></span>//由於不能確定start就是我們要的入口,插入一個jmp來條轉過去
- buf[0]=0xE9;//shortjmp
- (*(int*)(&buf[1]))=(int)func_entry-(int)fstart;//offset
- DWORDdwOldProtect;
- ::VirtualProtect(buf,abs(fs_empty-fs_addf)+100,PAGE_EXECUTE_READWRITE,&dwOldProtect);//之後buf就可以調用了
- typedefBOOL(__cdecl*PFN_CheckPass)(char*user,char*passwd);
- PFN_CheckPassfnCheck=(PFN_CheckPass)buf;
- printf("testCheckUserAndPass:
inputUser:"); - gets(bf_user);
- printf("inputPass:");
- gets(bf_pass);
- BOOLx=fnCheck(bf_user,bf_pass);
- printf("result:%d
",x); - return0;
- }
最後你可以用dump內存把shellcode dump到文件中,以便使用
推薦閱讀:
※如何少寫代碼,快速開發一個應用?
※回復貼圖代碼彙編2
※2014年最新交通違法代碼
※圖片製作的方法及代碼
※精美日誌邊框代碼·紫紅閃動邊框-