--- pmsdk/samples/spy/spyhstrt.asm 2018/08/09 12:28:12 1.1 +++ pmsdk/samples/spy/spyhstrt.asm 2018/08/09 12:28:20 1.1.1.2 @@ -1,18 +1,31 @@ ; SPYHOOK library initialization routine +; Created by Microsoft Corporation, 1989 -; Created by Microsoft Corp. 1987 +?WIN=1 ; Use Windows prolog/epilog +?PLM=1 ; Use PLM calling convention +DOS5=1 +.xlist +include cmacros.inc +.list + +; Define some constants to help build stack trace +savedCS = 4 +savedIP = 2 +savedBP = 0 +savedDS = -2 -_DATA segment - assume DS:_DATA +sBegin DATA +assumes DS,DATA public __acrtused __acrtused = 1 -_DATA ends +sEnd DATA -_TEXT SEGMENT WORD PUBLIC 'CODE' - assume cs:_TEXT - assume ds:_DATA +sBegin CODE +assumes cs,CODE +assumes ds,DATA EXTRN Init:NEAR +.286p ; ; Registers set up by DosLoadModule... @@ -21,14 +34,203 @@ EXTRN Init:NEAR ; DI = module ID ; DS = library's automatic data segment ; -LoadProc proc far +cProc LoadProc, +cBegin LoadProc push di call Init ; Init( hmod ); - ret 0 -LoadProc endp +cEnd LoadProc -_TEXT ends + + +; CopyStruct +; +; CopyStruct(pbSrc, pbDst, cb) +; +cProc CopyStruct,, +ParmD pbSrc +ParmD pbDest +ParmW cb +cBegin + + mov cx,cb + jcxz lcopydone ; all done if cb == 0 + + mov bx,seg_pbDest + lar ax,bx ; make sure we have access + jnz lcopyDone ; no access + les di,pbDest + + lsl ax,bx ; get the segment limit + mov bx,di ; check range + add bx,cx ; ending byte to copy + jc lcopyDone ; overflowed + cmp ax,bx + jc lcopyDone ; no room at destination + + mov bx,seg_pbSrc + lar ax,bx ; make sure we have access + jnz lcopyDone ; no access + + lds si,pbSrc + lsl ax,bx ; get the segment limit + mov bx,si ; check range + add bx,cx ; ending byte to copy + jc lcopyDone ; overflowed + cmp ax,bx + jc lcopyDone ; Source is not big enough + + cmp si,di + jae lcopyok + mov ax,cx + dec ax + add si,ax + add di,ax + std + rep movsb + cld + jmp short lcopydone +lcopyok: + cld + rep movsb +lcopydone: +cEnd + + + + +cProc BuildStackTrace,, +ParmD pStackSave +ParmW cCallsIgnore +ParmW cCallsSave + +cBegin + les di,pStackSave ; where to save away stack info + mov bx,bp + mov dx,ss + lsl dx,dx +; +; First we need to ignore the defined number of entries + mov cx,cCallsIgnore + jcxz SaveLoop ; Dont ignore any? +NextBPToIgnore: + and bx,0FFFEh ; Flush any INC BP bit + jz SaveLoop ; End of chain if zero + cmp bx,dx ; BP outside of stack segment? + jae SaveLoop ; Yes, end of chain + mov si,bx ; Save current BP + mov bx,ss:[bx].savedBP ; SS:BX -> next frame in BP chain + and bl,0FEh ; Flush any INC BP bit + cmp bx,si ; savedBP valid? + jbe SaveLoop ; No, end of chain + dec cx ; decrement count of calls to ignore + jnz NextBPToIgnore ; Process the next one + +; +; This loop will save away the specified number of calls into the +; passed in save area + +SaveLoop: + mov cx,cCallsSave ; get count of calls to save + +NextBPToSave: + and bx,0FFFEh ; Flush any INC BP bit + jz EndBPChain ; End of chain if zero + cmp bx,dx ; BP outside of stack segment? + jae EndBPChain ; Yes, end of chain +; see if short or long call and setup selLast + mov si,ss:[bx].savedCS ; Get the code segment + lar ax,si ; get the access rights + jnz CSNotValid ; No access assume not selector + and ah,018h ; see if code segment + cmp ah,018h ; + jz CSValid ; code segment, so save it + +CSNotValid: + xor si,si ; Not valid, set selector to NULL +CSValid: + mov ax,ss:[bx].savedIP ; save away IP of caller + stosw + mov ax,si ; and save away the code selector + stosw + dec cx ; decrement count of how many to save + + mov si,bx ; Save current BP + mov bx,ss:[bx].savedBP ; SS:BX -> next frame in BP chain + and bl,0FEh ; Flush any INC BP bit + cmp bx,si ; savedBP valid? + jbe EndBPChain ; No + jcxz StackOverflowsSave ; Stack is deeper than save area + + jmp NextBPToSave +; +; We reached the end of the BP chain before we saved the specified number +; of stack items. zero out the next item to signal caller how many items +; were filled in + +EndBPChain: + jcxz FillInSelectors + xor ax,ax ; Ended BP Chain Before count + stosw ; Put A 0:0 to signal end + stosw + sub di,4 ; realign DI to last saved call + mov ax,es:[di-2] ; ax = Selector of last saved call + jmp FillInSelectors ; + +; +; We saved the specified number of items, before we reached the end of the +; BP chain. If the last item we saved was a local call, we should continue +; to go through the stack until we find a valid far return address. + +StackOverflowsSave: + or ax,ax ; Was last call local? + jnz FillInSelectors ; + +; loop to locate a FAR return address +NextBPToCheck: + and bx,0FFFEh ; Flush any INC BP bit + jz FarReturnNotFound ; End of chain if zero + cmp bx,dx ; BP outside of stack segment? + jae FarReturnNotFound ; Yes, end of chain +; see if short or long call and setup selLast + mov ax,ss:[bx].savedCS ; Get the code segment + lar cx,ax ; get the access rights + jnz CSNotValid2 ; No access assume not selector + and ch,018h ; see if code segment + cmp ch,018h ; + jz FillInSelectors ; ax has valid code selector, use it + +CSNotValid2: + mov si,bx ; Save current BP + mov bx,ss:[bx].savedBP ; SS:BX -> next frame in BP chain + and bl,0FEh ; Flush any INC BP bit + cmp bx,si ; savedBP valid? + jg NextBPToCheck +FarReturnNotFound: + mov ax,0ffffh ; use special value to show + +; +; Loop through and convert all Short return addresses into long return +; addresses +; +FillInSelectors: + mov cx,off_pStackSave +FillInLoop: + cmp di,cx ; have we back tracked all the way? + jz FillInEnd ; Yes + sub di,4 ; point back to previous item + cmp WORD PTR es:[di+2],0 ; is the selector zero? + jz LocalReturn ; Yes, local return + mov ax,es:[di+2] ; No FAR return, save CS selector + jmp FillInLoop +LocalReturn: + mov es:[di+2],ax ; Make long return using saved CS + jmp FillInLoop + +FillInEnd: +cEnd + +sEnd CODE end LoadProc