first line on ASM


    .code64 #.code32 ==> this will confine to not use rsp
    #for all uses,an advance:
    #    do not mix '.code32' with 'as --64'
    #     use '.code32' with 'as --32' and '.code64' with 'as --64' correspondingly

    #some differences in 64    <=== 32:
    #    pop,push <=== pushl popl
    #    rsp,rbp <===== ebp,esp
    #        otherwise , just the low 4-byte is pushed
    /*
    new design:
        .ascii
            like "Hello world\0"
            \ is available, \0 is NOT automatically added
        .byte
        .int    ==>short
        .long    ==> in 64, it's 4-byte
    no jb,but jg

    */
    .section .data
arr:    .long 5,4,9,3,0
msg:    .ascii "Hello Wolrd\n.\0"
len     = . - msg
exit_message:    .ascii "exiting now.\0"
message_len = .- exit_message
    .section .text
    .global _start
_start:
    /*
    mov %cs,%ax
    pushw %ax
    call change_ds
    add $2,%rsp
    */
    push $arr #8-byte
    call find_max
#    addl $8,%esp  # in 32 , use pop instead. each pushl is 8
    #    popl!=addl , because 8-byte adding operation makes 0x7fffff4e28 by adding $0x8 into 0xffff4e28,0x7fff had disappeared
    add $8,%rsp

    #use ds to locate _start
    #_start 68 22 01 60 00
    movl %ds:_start,%eax
    movl %cs:_start,%ebx
    #RESULT : eax=ebx

    #    pushw $0x3b #cause cs=0x33,index is 0x110,0x3b index is 0x111---- this is failed,because when loading segment,the target segment must exist.
    pushw $0x2b #cause ss=0x2b,set it,only if it is different with cs
    call change_ds
    add    $2,%rsp
    #set an invalid descriptor for ds,see if ds will redirect to cs
    movl %ds:_start,%eax
    #===RESULT the same.This indicates ss.base=cs.base

    #===TEST : through cs,get the current stack
    mov $0x1111222233334444,%rax
    push %rax
    mov %rsp,%rbx
    mov %cs:(%rbx),%rcx
    #RESULT : rcx=(rsp)


    #set ss=0,will it act like the ds by just using cs?
    /*
    movw $0,%ax
    movw %ax,%ss
    mov %ss:(%rsp),%rdx
    */
    #RESULT : falied,you can't set ss=0

    #set ss=0x33-->cs
    /*
    movw $0x33,%ax
    movw %ax,%ss
    mov %ss:(%rsp),%rdx
    */
    #RESULT : falied to set ss=0x33 , cause CPL check.

    #===TEST :show message
    push $len
    push $msg
    call int_80_print
    add $16,%rsp
    #===RESULT : worked,showed message

    #===TEST ret_jmp: use push+ret to mock a jmp
    #set cs=ss
    #    ljmp $0xfebc, $0x12345678 -- can't ljmp. is unsupported
    pushw $0
    pushw $0
    mov $in_here,%eax
    movw %ax,%bx
    shr $16,%eax
    pushw %ax
    pushw %bx

    ret
    #===RESULT ret_jmp:
    #    not the same with lret_ljmp, ret will pop 8-byte into rip,the whole 8-byte is considered to be the rip's value
    #    jmp has some differences with ljmp
    #        jmp can move in a space from 0 ~ 64-bit in a segment
    #    while
    #        ljmp can only move in a space from 0 ~ 32 bit in a segment
    # pay attention to that,the space refered above is all virtual spaces in a process's segment.
    # also pay attention,
    #    cs will change nothing
    # so exactly, ret will do like this:
    #    ret =
    #        pop rip(8-byte)
    # again,note the difference with that in lret.
    
    #===RESULT : worked.The info "exiting now." printed

    # several problems:
    #    1.how to set CS,IP
    #    2.use ret,lret to mock jmp,ljmp
    #ret is just simplely pop the stack
in_here:
    #mov to cs will cause SIGKILL
    #still running fine will indicate that cs.base=ss.base and cs.PL>=ss.PL

    
    #The Whole test shows that, a segment descriptor may have the same base address , but have different privilage level

    #===TEST :use push+lret to mock ljmp,or to mock set %cs
    movw %cs,%ax
    pushw $0
    pushw %ax
    /*
    []*n
    []*m
    m=8
        n=8 not working
        n=4 not working
        n=2 not working
        n=12 not working
    m=4
        n=4 ===>working
    */
    movl $last_part,%eax
    movw %ax,%bx
    shr $16,%eax
    pushw %ax
    pushw %bx
    jmp set_csip
    #===RESULT : if set cs<===ss,then SIGSEGV is raised
    #        if set cs===>ss,the same thing goes happening
    #        but use cs-->ss,use cs<---ss are all fine
    #===RESULT 2:
    #    lcall new_cs,new_ip= (exactly,check the stack,you will know it)
    #        pushl old_cs(4-byte)
    #        pushl old_ip(4-byte)
    #        cs=new_cs
    #        ip=new_id
    #    lret    =
    #        pop 4-byte into 8-byte rip
    #        pop 4-byte into 2-byte cs
    #so concludingly,we can say lcall has a limitation that it's offset shall be no bigger than 4GB(2^32 Byte),no matter what the capacity of ram is
    # p.s ram capacity=2^addr_width_in_use * 8 bit
    # say , my computer addr_width_in_use=32,word_length=64
    #    capacity=4G*8 bit=4G*Byte=4GB
    # word_length cannot affect the bus, it is none bussiness with the actual capacity
    #    with addr_width_in_use=32 , the rip will just act like eip.Don't think that the higher 32 bit of rip will be used
last_part:    
    movl $0,%ebx
    call exit_proc
    # void int_80_print(str,len)
int_80_print:
    enter $0,$0
    movl $0x4,%eax
    movl $1,%ebx
    movl 16(%rbp),%ecx
    movl 24(%rbp),%edx
    int $0x80
    leave
    ret
    #void set_ip   ---- use jmp instead of call
set_ip:    
    ret
    #void set_csip  ---- use jmp instead of call
set_csip:
    lret
    
    # void exit_proc(ebx)
exit_proc:
    push $message_len
    push $exit_message
    call int_80_print
    add $16,%rsp
    
    movl $1,%eax
    int $0x80
    /*
    .global means don't discard symbols after compiling,cause ld will use it.
    and _start is a predefined symbol for ld to load address for cs.
    0x80
        void 1=exit(ebx)
            exit is a quick way to kill the process.Actually,exit is so speciall that even it has a return value,that value will never be catch.
            after this , echo $? will find the return code
    */

    # int find_max(addr)
    # .stdcall c
find_max:
    /*
    push %rbp
    mov %rsp,%rbp
    */
    enter $0,$0
    #the reason using ebp is that,esp will always change ,thus it is never sure where the arguments are.If ebp is always the hidden argument for a call,it can always be used to locate the arguments
    
    #example:
    #    movl 4(%esp),%esi
    #    movl (%esp),%esi  #===> esp-->last_ip
    #    last_ip is 8-byte long in --64 option
    #        thus should use 8(%esp) to get the first argument
    movl 16(%rbp),%esi
    movl %cs:(%esi),%eax
    addl $4,%esi
    #addq is 64-bit
    pushw %ax
    movw $0,%ax
    mov %ax,%ds
    popw %ax
local_here:
    movl %ds:(%esi),%ebx
    #finally we understand this,if we set ds as 0, then any ds prefix will be relocated to cs
    #because actually the data can be accessed by use %cs:
    #we can use ds to locate a data in cs , as if we're using cs
    testl %ebx,%ebx
    jz    local_end
    cmpl %eax,%ebx
    jbe     local_noupdate
    movl %ebx,%eax
local_noupdate:
    addl $4,%esi
    jmp local_here
local_end:
#    mov %rbp,%rsp
#    pop %rbp
    #equal to 'enter,and leave'
    leave
    /*
    []*8  arg1
    []*8  last_ip
    []*8  last_ebp  <--- rbp
    
    */
    ret

    # int find_max_perfect(addr)
find_max_perfect:    
    ret
    # void change_ds(seg_descriptor)
    # as the 80386 manual pointed out , a loading to ss,ds,cs,xs in protected mode will result in some extra actions,like check the value if it is null,set the invisible bit
    # pop 0x0~0x3 into those registers will casue no exception
change_ds:
    enter $0,$0
    #suffix sometimes are not needed
    mov 16(%rbp),%ax
    mov %ax,%ds
    leave
    ret

posted @ 2016-11-10 20:45  Douglas_at_HIT  阅读(104)  评论(0编辑  收藏  举报