Announcement

Collapse
No announcement yet.

Modernise security with stack randomisation

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Modernise security with stack randomisation

    Recent Microsoft linkers have the option of stack randomisation. This technique performs the task in a different manner, it adjusts the stack pointer dynamically at the application's entry point across a random range so that the stack pointer is different every time the app starts.
    Code:
        GLOBAL tcnt         as DWORD
        GLOBAL seed         as DWORD
        GLOBAL rand         as DWORD
        GLOBAL lcnt         as DWORD
        GLOBAL bstp         as DWORD
    
    ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
    FUNCTION PBmain() AS LONG
    
        tcnt = GetTickCount     ' get a number sample
        ! mov eax, tcnt
        ! bswap eax             ' invert byte order
        ! mov seed, eax         ' store it as a seed
    
        ! mov lcnt, 64          ' loop iteration count
        RANDOMIZE seed          ' set seed as base for rnd
      lbl:
        rand = RND(1, 32)       ' random numbers in the range of 1 to 32
        ! sub lcnt, 1
        ! jnz lbl
    
        ! mov eax, rand         ' load rnd result into eax
        ! shl eax, 4            ' mul by 16  original side comment had not been updated but the code is correct
    
        ! sub esp, eax          ' subtract result from stack pointer
        ! mov bstp, esp         ' a copy of ESP after mod
    
        Startup
    
    END FUNCTION
    
    ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    It uses GLOBAL scope variables as LOCAL variable are created on the stack and this code MUST be placed at the start of the entry point. All of the application code must come after it.

    The virtue of this approach is it protects the app from certain types of stack exploits.
    Attached Files
    Last edited by Steve Hutchesson; 11 Oct 2022, 03:53 AM. Reason: Edit due to a side comment not being updated
    hutch at movsd dot com
    The MASM Forum - SLL Modules and PB Libraries

    http://www.masm32.com/board/index.php?board=69.0

    #2
    Interesting

    a small note -
    ! shl eax, 4 ' mul by 8
    should be
    ! shl eax, 4 ' mul by 16 '<<---- edit: this one per next post
    or
    ! shl eax, 3 ' mul by 8

    cheers,
    Last edited by Dale Yarker; 11 Oct 2022, 02:57 AM.
    Dale

    Comment


      #3
      Yes you are right, I did not update the side comment but the code "shl eax, 4" is the intended design.
      hutch at movsd dot com
      The MASM Forum - SLL Modules and PB Libraries

      http://www.masm32.com/board/index.php?board=69.0

      Comment


        #4
        Thanks so much, Steve

        However, you have use several globals here, can these globals be made LOCALs ?
        since we only need to use the Startup function one time only.

        Using too many globals may lead to clashes with other variable names for a large program?


        Code:
        GLOBAL tcnt as DWORD
        GLOBAL seed as DWORD
        GLOBAL rand as DWORD
        GLOBAL lcnt as DWORD
        GLOBAL bstp as DWORD​

        Comment


          #5
          Steve

          Is this an antihacking tool?
          [I]I made a coding error once - but fortunately I fixed it before anyone noticed[/I]
          Kerry Farmer

          Comment


            #6
            Originally posted by Anne Wilson View Post
            Using too many globals may lead to clashes with other variable names for a large program?
            Not if you use an appropriate naming convention
            I generally use an initial "g" for global, followed by lower case type identifier, followed by a capitalised meaningful name
            Code:
            GLOBAL gdwTcnt as DWORD
            GLOBAL gdwSeed as DWORD
            GLOBAL gdwRand as DWORD
            GLOBAL gdwLcnt as DWORD
            GLOBAL gdwBstp as DWORD​
            Alternatively, if you really don't like lots of globals, you could go with something like and only have one global :
            Code:
            #COMPILE EXE
            #DIM ALL
            
            TYPE Globals
            dwTcnt AS DWORD
            dwSeed AS DWORD
            dwRand AS DWORD
            dwLcnt AS DWORD
            dwBstp AS DWORD
            END TYPE
            GLOBAL glob AS Globals
            
            FUNCTION PBMAIN() AS LONG
                glob.dwRand = 4 ' 4 selected by random throw of a die :)
                ...
            END FUNCTION
            =========================
            https://camcopng.com
            =========================

            Comment


              #7
              Anne,

              Go back to post 1 and read it this time! Hint - sentence after code.
              Dale

              Comment


                #8
                Anne,

                > Using too many globals may lead to clashes with other variable names for a large program?

                If you were going to use this example, you would pick names that will not be duplicated elsewhere in your app. Var_@@@_123_etc

                They cannot be LOCAL as a local variable is written to the stack which is being modified in this example. As long as they are unique, globals work fine.

                Kerry,

                Its a technique to randomise the stack address in ESP so that certain types of stack exploits will no longer work. Later languages (M$ C/C++) for example have a linker option to randomise the stack, this is an alternative method for PB as it did not have one built in.
                hutch at movsd dot com
                The MASM Forum - SLL Modules and PB Libraries

                http://www.masm32.com/board/index.php?board=69.0

                Comment


                  #9
                  Steve, what is WINMAIN and SDK-Style?

                  Comment


                    #10
                    (Thread hijack Norbert, WINMAIN and SDK-Style not mentioned elsewhere in thread.)
                    WINMAIN discussed in help.
                    SDK is using Windows API instead of PB DDT.
                    Ask more in new thread.
                    Dale

                    Comment


                      #11
                      Hi Norbert,

                      I started another topic for you.
                      hutch at movsd dot com
                      The MASM Forum - SLL Modules and PB Libraries

                      http://www.masm32.com/board/index.php?board=69.0

                      Comment


                        #12
                        Hi Steve,

                        nice code!

                        PB builds EBP-based stack frames, so no need to use globals, locals work as well. EBP is used to reference locals, the actual value of ESP doesn´t matter here.

                        Code:
                        local tcnt         as DWORD
                        local seed         as DWORD
                        local rand         as DWORD
                        local lcnt         as DWORD
                        'local bstp         as DWORD
                        ​
                        if you don´t need "bstp" outside of PBMAIN, it can be local too.

                        JK

                        Comment


                          #13
                          Hi Juergen,

                          The variable "bstp" is for later reference, you can save ESP before the mod or after and use it to check if the app has been hacked. I put them all together for convenience as I have no problems with GLOBAL values. Stack exploits are based off ESP, not EBP so I have modified ESP to address that situation. What you need to determine is if a stack based exploit will succeed if you use LOCAL rather than GLOBAL variables.

                          The suggestion above is an easy way to protect against stack exploits as it will be different each time the app starts.
                          hutch at movsd dot com
                          The MASM Forum - SLL Modules and PB Libraries

                          http://www.masm32.com/board/index.php?board=69.0

                          Comment


                            #14
                            Steve,

                            i absolutely understand, what you do!

                            My point was, that you don´t need globals (maybe except for "bstp", which btw, could as well be passed down the procedure chain for later tests) it works quite well with locals. In post #4 Anne complained about the use of globals, and after having a look at it, i found it works with locals as well. You could even define and use a macro for that.

                            So, for me there is no problem using globals (a great feature, if properly used - i do it a lot myself), but the message for those, who don´t want to/cannot use globals, is: it also works with locals ...

                            JK

                            Comment


                              #15
                              Morning effort before I go out for my morning coffee. Free of GLOBAL and LOCAL variables. The seed_rrand algo must use GLOBAL values for the rrand algo, the two GLOBAL values below are purely for testing the results to respond to any modification by a stack exploit.

                              The problem is this code even though it works well is about as intuitive as a bucket of mud. The first example is simple and uses some standard basic that most will understand where this one while being more powerful is specialised as full assembler.

                              Code:
                                  GLOBAL preesp       as DWORD        ' stack pointer before mod
                                  GLOBAL pstesp       as DWORD        ' stack pointer after mod
                              
                              ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                              
                              FUNCTION PBmain() AS LONG
                              
                                  #REGISTER NONE
                              
                                  ! mov preesp, esp       ' store ESP default
                              
                                ' --------------------
                                ' randomise loop count
                                ' --------------------
                                  ! rdtsc                 ' get a fast changing number from the processor
                                  ! bswap eax             ' invert it to get the fast changing end
                                  ! push eax
                                  ! call seed_rrand       ' seed rrand
                                  ! push 64
                                  ! push 16
                                  ! call rrand
                                  ! mov esi, eax          ' loop counter
                              
                                ' --------------------
                                ' randomise stack
                                ' --------------------
                                  ! rdtsc                 ' get a fast changing number from the processor
                                  ! bswap eax             ' invert it to get the fast changing end
                                  ! push eax
                                  ! call seed_rrand       ' seed rrand
                              
                                lbl:
                                  ! push 64
                                  ! push 1
                                  ! call rrand
                                  ! sub esi, 1
                                  ! jnz lbl
                              
                                  ! shl eax, 4            ' mul by 16
                              
                                  ! sub esp, eax          ' subtract result from stack pointer
                              
                                  ! mov pstesp, esp       ' store modified ESP
                              
                                  Startup
                              
                              END FUNCTION
                              
                              ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                              Attached Files
                              hutch at movsd dot com
                              The MASM Forum - SLL Modules and PB Libraries

                              http://www.masm32.com/board/index.php?board=69.0

                              Comment


                                #16
                                Steve

                                I tried using your method 1 (post #1) and method 2 (post #15) with the following program

                                Code:
                                ' Transient MsgBox RandStack.bas
                                
                                '  Transient message box which closes by itself after some time
                                '  it has animation blinking message
                                
                                ' It incorporates the Randomized Stack routines by Steve
                                
                                
                                #COMPILE EXE
                                #DIM ALL
                                #INCLUDE "win32api.inc"
                                
                                
                                
                                
                                ENUM controlnumbers SINGULAR
                                    ID_MsgGrafix = 500
                                    ID_countdown
                                END ENUM
                                
                                 ' for Stack1 method
                                  GLOBAL bstp  AS DWORD
                                
                                
                                 ' for Stack2 method
                                   GLOBAL preesp       AS DWORD        ' stack pointer before mod
                                   GLOBAL pstesp       AS DWORD        ' stack pointer after mod
                                
                                
                                '=============================
                                FUNCTION PBMAIN () AS LONG
                                
                                     GitRandNum_Stack2
                                     DispTransientMsgBox
                                
                                END FUNCTION
                                
                                
                                
                                
                                
                                
                                
                                
                                
                                
                                '======================================
                                ' initialize some random numbers
                                ' to feed stack pointer  (by Steve Hutchinson )
                                ' method 1
                                ' https://forum.powerbasic.com/forum/user-to-user-discussions/powerbasic-inline-assembler/819409-modernise-security-with-stack-randomisation#post819409
                                SUB GitRandNum_Stack1
                                    LOCAL tcnt         AS DWORD
                                    LOCAL seed         AS DWORD
                                    LOCAL rand         AS DWORD
                                    LOCAL lcnt         AS DWORD
                                
                                    tcnt = GetTickCount     ' get a number sample
                                    ! mov eax, tcnt
                                    ! bswap eax             ' invert byte order
                                    ! mov seed, eax         ' store it as a seed
                                
                                    ! mov lcnt, 64          ' loop iteration count
                                    RANDOMIZE seed          ' set seed as base for rnd
                                  lbl:
                                    rand = RND(1, 32)       ' random numbers in the range of 1 to 32
                                    ! sub lcnt, 1
                                    ! jnz lbl
                                
                                    ! mov eax, rand         ' load rnd result into eax
                                    ! shl eax, 4            ' mul by 16  original side comment had not been updated but the code is correct
                                
                                    ! sub esp, eax          ' subtract result from stack pointer
                                    ! mov bstp, esp         ' a copy of ESP after mod
                                
                                END SUB
                                
                                
                                '======================================
                                ' initialize some random numbers
                                ' to feed stack pointer  (by Steve Hutchinson )
                                ' method 2
                                ' https://forum.powerbasic.com/forum/user-to-user-discussions/powerbasic-inline-assembler/819409-modernise-security-with-stack-randomisation?p=819498#post819498
                                SUB GitRandNum_Stack2
                                  #REGISTER NONE
                                
                                
                                
                                    ! mov preesp, esp       ' store ESP default
                                
                                  ' --------------------
                                  ' randomise loop count
                                  ' --------------------
                                    ! rdtsc                 ' get a fast changing number from the processor
                                    ! bswap eax             ' invert it to get the fast changing end
                                    ! push eax
                                    ! call seed_rrand       ' seed rrand
                                    ! push 64
                                    ! push 16
                                    ! call rrand
                                    ! mov esi, eax          ' loop counter
                                
                                  ' --------------------
                                  ' randomise stack
                                  ' --------------------
                                    ! rdtsc                 ' get a fast changing number from the processor
                                    ! bswap eax             ' invert it to get the fast changing end
                                    ! push eax
                                    ! call seed_rrand       ' seed rrand
                                
                                  lbl:
                                    ! push 64
                                    ! push 1
                                    ! call rrand
                                    ! sub esi, 1
                                    ! jnz lbl
                                
                                    ! shl eax, 4            ' mul by 16
                                
                                    ! sub esp, eax          ' subtract result from stack pointer
                                
                                    ! mov pstesp, esp       ' store modified ESP
                                
                                
                                
                                END SUB
                                
                                
                                ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                                
                                  FASTPROC seed_rrand
                                
                                    GLOBAL rrand____seed AS DWORD
                                    GLOBAL rrand____padd AS DWORD
                                
                                    ! mov eax, [esp+4]
                                    ! mov rrand____seed, eax
                                
                                    ! ret 4
                                
                                 END FASTPROC
                                
                                ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                                
                                 FUNCTION rrand(BYVAL lowest AS DWORD,BYVAL highest AS DWORD) AS DWORD
                                
                                    #REGISTER NONE
                                
                                  PREFIX "!"
                                  ; ----------------------
                                  ; generate random number
                                  ; ----------------------
                                    mov eax, rrand____seed
                                    mov edx, rrand____padd
                                    mov rrand____seed, edx
                                    mov ecx, eax
                                    shl ecx, 13
                                    xor eax, ecx
                                    mov ecx, eax
                                    xor ecx, edx
                                    shr eax, 19
                                    xor ecx, eax
                                    mov eax, edx
                                    shr eax, 31
                                    xor ecx, eax
                                    mov rrand____seed, ecx
                                    lea eax, [edx+ecx]
                                    bswap eax
                                
                                  ' --------------------------
                                  ' convert it to within range
                                  ' --------------------------
                                    mov ecx, highest                    ; load highest into ecx
                                    sub ecx, lowest                     ; sub lowest from it
                                    add ecx, 1                          ; correct the range
                                    div ecx                             ; divide eax by highest range value
                                    mov eax, edx                        ; copy division remainder into eax
                                    add eax, lowest                     ; add lowest to get correct range
                                    mov FUNCTION, eax                   ; return value in eax
                                
                                  END PREFIX
                                
                                 END FUNCTION
                                
                                ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                                
                                
                                
                                
                                 '==============================
                                 ' Display the Transient message box
                                 SUB  DispTransientMsgBox
                                 LOCAL hMsgWin AS DWORD, Lreturnval AS LONG
                                    DIALOG NEW PIXELS, 0, "", , ,400, 80, _
                                          %WS_POPUP OR %WS_BORDER TO hMsgWin
                                
                                    CONTROL ADD GRAPHIC, hMsgWin, %ID_MsgGrafix, "", _
                                           0, 0, 400, 80, %SS_NOTIFY OR %WS_BORDER
                                    DIALOG SHOW MODAL hMsgWin, CALL MsgDlgProc TO Lreturnval
                                
                                 END SUB
                                
                                
                                
                                
                                '==================================
                                ' Callback function for the Transient message box
                                CALLBACK FUNCTION MsgDlgProc() AS LONG
                                    STATIC downcount AS LONG
                                
                                    LOCAL  hFONT9_bold AS DWORD
                                    ' Bold font for the label
                                    FONT NEW "Arial",9,1 TO hFONT9_bold
                                
                                    SELECT CASE CB.MSG
                                
                                        CASE %WM_INITDIALOG
                                            settimer(CB.HNDL, %ID_countdown , 500, 0)
                                            ' Change this to allocate the time to close down message box
                                            downcount = 10
                                
                                            GRAPHIC ATTACH CB.HNDL, %ID_MsgGrafix
                                            GRAPHIC COLOR %RGB_CRIMSON, %RGB_ALICEBLUE
                                            GRAPHIC CLEAR
                                            GRAPHIC SET FONT hFONT9_bold
                                            GRAPHIC SET POS (10, 25)
                                           ' using stack randomizer method 1
                                         '   GRAPHIC PRINT "Please wait ... computation in progress  Stack pointer: "+STR$(bstp)
                                
                                           ' using stack randomizer method 2  -- did not work?
                                            GRAPHIC PRINT "Please wait ... computation in progress  Stack pointer: "+STR$(pstesp)
                                
                                          '  this is to display Countdown message  -- display only when needed
                                          '  GRAPHIC COLOR %RGB_DARKGREEN, %RGB_ALICEBLUE
                                          '  GRAPHIC SET POS (30, 50)
                                          '  GRAPHIC PRINT "Countdown  " + TRIM$(downcount) + "     "
                                
                                
                                        CASE %WM_TIMER
                                            GRAPHIC ATTACH CB.HNDL, %ID_MsgGrafix
                                            SELECT CASE CB.CTL
                                
                                                CASE %ID_countdown
                                                  '  this is to display Countdown message  -- display only when needed
                                                  '  GRAPHIC COLOR %RGB_DARKGREEN, %RGB_ALICEBLUE
                                                  '  GRAPHIC SET POS (30, 50)
                                                  '  GRAPHIC PRINT "Countdown: " + TRIM$(downcount) + "     "
                                
                                
                                                  ' Alternate display of thick frame border or no border on dialog
                                                  ' changes with each countdown -- like a heartbeat
                                                  ' if want rapid blinking reduce the timer time
                                             SetWindowLong GetDlgItem(CB.HNDL, %ID_MsgGrafix), %GWL_STYLE, _
                                                   GetWindowLong(GetDlgItem(CB.HNDL, %ID_MsgGrafix), %GWL_STYLE) XOR %WS_BORDER
                                             SetWindowPos GetDlgItem(CB.HNDL, %ID_MsgGrafix),0,0,0,0,0,_
                                             %SWP_NoMove OR %SWP_NoSize OR %SWP_DrawFrame
                                
                                                     DECR downcount
                                                    ' modified to close the application
                                                    ' when downcount < 0
                                                    ' (about 10 secs if we start with downcount= 10)
                                                    IF downcount < 0 THEN
                                                        killtimer(CB.HNDL, %ID_countdown )
                                                        DestroyWindow  CB.HNDL
                                                    END IF
                                
                                            END SELECT
                                
                                
                                    END SELECT
                                END FUNCTION​
                                Both methods work and method 2 gives more randomized pointers
                                Did I do anything wrong here?

                                Comment


                                  #17
                                  Code:
                                  '==================================
                                  ' Callback function for the Transient message box
                                  CALLBACK FUNCTION MsgDlgProc() AS LONG
                                  STATIC downcount AS LONG
                                  
                                  LOCAL hFONT9_bold AS DWORD
                                  ' Bold font for the label
                                  FONT NEW "Arial",9,1 TO hFONT9_bold​
                                  ...
                                  Really?
                                  You create a new font with EVERY Callback message to the dialog including every %WM_TIMER?
                                  DO you know what a memory leak is?
                                  =========================
                                  https://camcopng.com
                                  =========================

                                  Comment


                                    #18
                                    Hi Anne,

                                    If it worked, it worked, the second one has a wider number range so you will get a wider spread of random stack offsets.
                                    hutch at movsd dot com
                                    The MASM Forum - SLL Modules and PB Libraries

                                    http://www.masm32.com/board/index.php?board=69.0

                                    Comment


                                      #19
                                      Originally posted by Steve Hutchesson View Post
                                      Hi Anne,

                                      If it worked, it worked, the second one has a wider number range so you will get a wider spread of random stack offsets.
                                      A very dedicated hacker will check each of the random offsets.
                                      But will that even work to find the actual entry point?
                                      Would they just be whistling in the dark in attempting to identify the entry point then?
                                      The world is strange and wonderful.*
                                      I reserve the right to be horrifically wrong.
                                      Please maintain a safe following distance.
                                      *wonderful sold separately.

                                      Comment


                                        #20
                                        Kurt,

                                        The entry point in a disassembler is easy to find and you can find the above code directly after the PB entry and setup code but the two globals for ESP, before and after modification are easily buried in any reasonable sized application and being able to test if the default stack value has been restored (after deleting the code after the entry point) or setting a different value to the modified one is easy enough to detect and respond to.

                                        You can see anything get broken if the attacker knows enough and is patient enough but they will work hard to do it and this is not common for a stack exploit, its mainly dead listing hacks that do stuff like this.
                                        hutch at movsd dot com
                                        The MASM Forum - SLL Modules and PB Libraries

                                        http://www.masm32.com/board/index.php?board=69.0

                                        Comment

                                        Working...
                                        X
                                        😀
                                        🥰
                                        🤢
                                        😎
                                        😡
                                        👍
                                        👎