首页
社区
课程
招聘
[旧帖] [原创]大牛的小bug,对某Windows x64 shellcode的一点改进 0.00雪花
2012-4-23 20:40 2770

[旧帖] [原创]大牛的小bug,对某Windows x64 shellcode的一点改进 0.00雪花

2012-4-23 20:40
2770
本人新人,但是关注看雪前辈、大牛们的文章很久了,确实受益匪浅~最近一段时间对windows x64 shellcode比较感兴趣,发现看雪里有一些很好的文章,同时从互联网上看到几个页面,写了这方面,很好:1、http://www.cdut-boy.com/tag/shellcode/ 2、http://mcdermottcybersecurity.com/articles/windows-x64-shellcode,其中第二篇写得更棒,Bill McDermott写的,崇拜and敬仰~
    于是,拿他的代码去机器上调试,结果测出了一点问题,具体如下:
    他说,
 
    lea rdx, loadlib_func
    lea rcx, kernel32_dll
    call lookup_api         ;get address of LoadLibraryA
    mov r15, rax            ;save for later use with forwarded exports
 
    lea rcx, user32_dll
    call rax                ;load user32.dll
 
    lea rdx, msgbox_func
    lea rcx, user32_dll
    call lookup_api         ;get address of MessageBoxA
 
    xor r9, r9              ;MB_OK
    lea r8, title_str       ;caption
    lea rdx, hello_str      ;Hello world
    xor rcx, rcx            ;hWnd (NULL)
    call rax                ;display message box

    kernel32_dll    db  'KERNEL32.DLL', 0
    loadlib_func    db  'LoadLibraryA', 0
    user32_dll      db  'USER32.DLL', 0
    msgbox_func     db  'MessageBoxA', 0
    hello_str       db  'Hello world', 0
    title_str       db  'Message', 0


通过以上代码就可以,跳出一个messagebox,没错确实可以的,但是我把代码做了下修改,出问题了(我的代码在goasm下编译,语法有相应修改)
        Lea rdx, str_loadlib_func
	Lea rcx, str_kernel32_dll
	Call lookup_api         ;get address of LoadLibraryA,rax=LoadLibraryA
	Mov r15, rax

	Lea rdx, str_create_thread
	Lea rcx, str_kernel32_dll
	Call lookup_api         ;get address of createthread to rax

        str_kernel32_dll: DB 'KERNEL32.DLL', 0H
        str_loadlib_func: DB 'LoadLibraryA', 0H
        str_create_thread: DB 'CreateThread', 0H


调用createthread  api函数时,程序出现异常,退出了~写程序调试一下看问题出在哪里:
    Invoke LoadLibrary, Addr str_kernel32_dll
    Invoke GetProcAddress, rax, Addr str_create_thread
    Int 3
    Lea rdx, str_loadlib_func
    Lea rcx, str_kernel32_dll
    Call lookup_api         ;get address of LoadLibraryA,rax=LoadLibraryA
    Mov r15, rax
    Int 3

    Lea rdx, str_create_thread
    Lea rcx, str_kernel32_dll
    Call lookup_api         ;get address of createthread to rax
    Int 3

    Ret

    str_kernel32_dll: DB 'KERNEL32.DLL', 0H
    str_loadlib_func: DB 'LoadLibraryA', 0H
    str_create_thread: DB 'CreateThread', 0H

用windbg断住每个int3,看正确的createthread地址 与我们获取的有什么不同。
这是第一个int 3现场

注意rax的值是76fa6210h,这是createthread的正确地址,再看第三个int 3中断现场

rax的值是76f9a6a0h,与正确值76fa6210h不一样,显然是错了,那为什么呢?
windbg跟踪一下lookup_api 函数,发现问题了,这是调试过程中的一个现场,
注意到这里lookup_api 函数已经匹配成功了,是字符串“CreateThread”,但是我们看看rdi指向的地址77034584h,是什么呢?图片右下角列出来了“poolWork...”,当然,这不重要,重要的是它的前面是“CreateThread”,哈哈,问题找到了,代码作者做字符串匹配有个小bug,把“CreateThreadpoolWork”当成“CreateThread”了,因此获取了错误的函数地址。ok,拿出修改意见,还是goasm风格的:
    ;look up address of function from DLL export table
    ;rcx=DLL name string, rdx=function name string
    ;DLL name must be in .lookup_api_uppercase
    ;r15=address of LoadLibraryA (optional, needed if export is forwarded)
    ;returns address in rax
    ;returns 0 if DLL not loaded or exported function not found in DLL
    ;lookup_api func
lookup_api:
    	Sub rsp, 28H            ;set up stack frame in case we call loadlibrary
        Call get_offset
        Add rdx, r14
        Add rcx, r14
.lookup_api_start
    	Push 60H
        Pop rax
    	DB 65H, 4CH, 8BH, 00H   ;Mov r8, Gs:[rax]   peb
    	Mov r8, [r8 + 18H]      ;peb loader data
    	Lea r12, [r8 + 10H]     ;InLoadOrderModuleList (list head) - save for later
    	Mov r8, [r12]           ;follow _LIST_ENTRY->Flink to first item in list
    	Cld

.lookup_api_for_each_dll                  ;r8 points to current _ldr_data_table_entry

    	Mov rdi, [r8 + 60H]     ;UNICODE_STRING at 58h, actual string buffer at 60h
   		Mov rsi, rcx            ;pointer to dll we're looking for

.lookup_api_compare_dll
    	Lodsb ;load character of our dll name string
    	Test Al, Al             ;check for null terminator
    	Jz >.lookup_api_found_dll            ;if at the end of our string and all matched so far, found it

    	Mov Ah, [rdi]           ;get character of current dll
    	Cmp Ah, 61H             ;lowercase 'a'
    	Jl >.lookup_api_uppercase
    	Sub Ah, 20H             ;convert to uppercase
.lookup_api_uppercase
    	Cmp Ah, Al
    	Jne >.lookup_api_wrong_dll           ;found a character mismatch - try next dll

    	Inc rdi                 ;skip to next unicode character
    	Inc rdi
    	Jmp .lookup_api_compare_dll         ;continue string comparison

.lookup_api_wrong_dll
    	Mov r8, [r8]            ;move to next _list_entry (following Flink pointer)
    	Cmp r8, r12             ;see if we're back at the list head (circular list)
    	Jne .lookup_api_for_each_dll

    	Xor rax, rax            ;DLL not found
    	Jmp >>.lookup_api_done

.lookup_api_found_dll
    	Mov rbx, [r8 + 30H]     ;get dll base addr - points to DOS "MZ" header
    	Mov r9d, [rbx + 3CH]    ;get DOS header e_lfanew field for offset to "PE" header
    	Add r9, rbx             ;add to base - now r9 points to _image_nt_headers64
    	Add r9, 88H             ;18h to optional header + 70h to data directories
                                ;r9 now points to _image_data_directory[0] array entry
                                ;which is the export directory

   		Mov r13d, [r9]          ;get virtual address of export directory
    	Test r13, r13           ;if zero, module does not have export table
    	Jnz >.lookup_api_has_exports

   		Xor rax, rax            ;no exports - function will not be found in dll
    	Jmp >>.lookup_api_done

.lookup_api_has_exports
    	Lea r8, [rbx + r13]     ;add dll base to get actual memory address
                                ;r8 points to _image_export_directory structure (see winnt.h)

    	Mov r14d, [r9 + 4]      ;get size of export directory
    	Add r14, r13            ;add base rva of export directory
                                ;r13 and r14 now contain range of export directory
                                ;will be used later to check if export is forwarded

    	Mov Ecx, [r8 + 18H]     ;NumberOfNames
    	Mov r10d, [r8 + 20H]    ;AddressOfNames (array of RVAs)
    	Add r10, rbx            ;add dll base

    	Dec Ecx                 ;point to last element in array (searching backwards)
.lookup_api_for_each_func
    	Lea r9, [r10 + 4 * rcx] ;get current index in names array

    	Mov Edi, [r9]           ;get RVA of name
    	Add rdi, rbx            ;add base
    	Mov rsi, rdx            ;pointer to function we're looking for

.lookup_api_compare_func
    	Cmpsb
    	Jne >.lookup_api_wrong_func          ;function name doesn't match

    	Mov Al, [rsi]           ;current character of our function
    	Test Al, Al             ;check for null terminator
    	Jnz >.lookup_api_have_not_found
    	Mov Al, [rdi]
    	Test Al, Al
    	Jz >.lookup_api_found_func           ;if at the end of our string and all matched so far, found it
.lookup_api_have_not_found
    	Jmp .lookup_api_compare_func        ;continue string comparison

.lookup_api_wrong_func
    	Loop .lookup_api_for_each_func      ;try next function in array

    	Xor rax, rax            ;function not found in export table
    	Jmp >>.lookup_api_done

.lookup_api_found_func          ;ecx is array index where function name found

                                ;r8 points to _image_export_directory structure
    	Mov r9d, [r8 + 24H]     ;AddressOfNameOrdinals (rva)
    	Add r9, rbx             ;add dll base address
    	Mov Cx, [r9 + 2 * rcx]  ;get ordinal value from array of words

    	Mov r9d, [r8 + 1CH]     ;AddressOfFunctions (rva)
    	Add r9, rbx             ;add dll base address
    	Mov Eax, [r9 + rcx * 4] ;Get RVA of function using index

    	Cmp rax, r13            ;see if func rva falls within range of export dir
    	Jl >.lookup_api_not_forwarded
    	Cmp rax, r14            ;if r13 <= func < r14 then forwarded
    	Jae >.lookup_api_not_forwarded

    ;forwarded function address points to a string of the form <DLL name>.<function>
    ;note: dll name will be in .lookup_api_uppercase
    ;extract the DLL name and add ".DLL"

    	Lea rsi, [rax + rbx]    ;add base address to rva to get forwarded function name
    	Lea rdi, [rsp + 30H]    ;using register storage space on stack as a work area
    	Mov r12, rdi            ;save pointer to beginning of string

.lookup_api_copy_dll_name
    	Movsb
    	Cmp B[rsi], 2EH  ;check for '.' (period) character
    	Jne .lookup_api_copy_dll_name

    	Movsb ;also copy period
    	Mov D[rdi], 004C4C44H ;add "DLL" extension and null terminator

    	Mov rcx, r12            ;r12 points to "<DLL name>.DLL" string on stack
    	Call r15                ;call LoadLibraryA with target dll

    	Mov rcx, r12            ;target dll name
    	Mov rdx, rsi            ;target function name
    	Jmp .lookup_api_start    ;start over with new parameters

.lookup_api_not_forwarded
    	Add rax, rbx            ;add base addr to rva to get function address
.lookup_api_done
    	Add rsp, 28H            ;clean up stack
    	Ret
lookup_api_end:
;lookup_api endp

经测试,这个没有问题。
最后顺便问一下,这个createthread每次算出来的地址都是76fa6210,win 7 x64 的aslr干什么去了??

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
点赞3
打赏
分享
最新回复 (6)
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
oldyoung 2012-4-24 08:06
2
0
沙发~那个老外的文章确实很棒,不过内容很多啊,需要仔细研究~
貌似坛子里搞x64 shellcode的仁兄不多啊~新手区就更少了
雪    币: 45
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
YangAdou 2012-4-24 09:39
3
0
是啊~搞x64汇编的弟兄现在还不多,但是x64是趋势吧~
我后边贴出来的那个改进的lookup_api是可以直接用的,注意呦
雪    币: 609
活跃值: (172)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
小覃 2 2012-4-24 19:15
4
0
厉害啊,收藏了~~
雪    币: 47
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
rmlgwu 2012-4-24 19:24
5
0
楼主精神可嘉,一起学习!
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zqpzqp 2012-4-24 22:23
6
0
崇拜楼主,准备花一个月时间消化,顶起。。。
雪    币: 236
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
adwardwang 2012-4-25 19:53
7
0
不错,不错,分析挺细致,对要学习x64 shellcode的人能起到很大帮助
游客
登录 | 注册 方可回帖
返回