__inline VOID SortFromBounds ( WORD cbnds, LPBNDS rgbnds, WORD cv, LPV rgv, WORD cbv ) { LPV lpv = MHAlloc (cbv * cv); WORD ibnds = 0; WORD iv = 0; if (lpv == NULL) { return; } for (ibnds = 0; ibnds < cbnds; ibnds++) { WORD cvT = rgbnds [ ibnds ].ilnEnd - rgbnds [ ibnds ].ilnStart + 1; memcpy(((LPB) lpv) + (iv * cbv), ((LPB) rgv) + (rgbnds[ibnds].ilnStart * cbv), cvT * cbv); iv += cvT; } memcpy(rgv, lpv, cbv * cv); MHFree(lpv); }
VOID SHFree( LPV lpv ) { MHFree (lpv); }
LOCAL HST HstFromLpmds ( LPMDS lpmds ) { if (lpmds->hst != NULL) { return lpmds->hst; } else if (lpmds->pmod) { // Allocate space for this module's line number information, // then load it from the PDB and sort it. if (!ModQueryLines(lpmds->pmod, 0, (CB *)&lpmds->cbhst) || !(lpmds->cbhst) || !(lpmds->hst = MHAlloc(lpmds->cbhst))) return 0; if (ModQueryLines(lpmds->pmod, (PB)lpmds->hst, (CB *)&lpmds->cbhst)) { SortSM((LPSM)lpmds->hst); return lpmds->hst; } else { MHFree(lpmds->hst); lpmds->hst = 0; return 0; } } else if (lpmds->ulhst == 0) { return NULL; } else { assert(FALSE); // We should never hit this code now // that we're mapped. LPEXG lpexg = (LPEXG) LLLock (lpmds->hexg); HANDLE hfile = SYOpen (lpexg->lszDebug); HST hst = MHAlloc ((UINT) lpmds->cbhst); if (hfile == INVALID_HANDLE_VALUE || hst == NULL) { LLUnlock (lpmds->hexg); return NULL; } if (SYSeek(hfile, lpmds->ulhst, SEEK_SET) != (LONG) lpmds->ulhst) { assert(FALSE); } if (SYReadFar (hfile, (LPB) hst, (UINT) lpmds->cbhst) != lpmds->cbhst) { assert (FALSE); } SYClose (hfile); lpmds->hst = hst; LLUnlock (lpmds->hexg); SortSM ((LPSM)hst); return hst; } }
__inline VOID SortSL ( LPSL lpsl ) { WORD coff = lpsl->cLnOff; LPUL rgoff = lpsl->offset; LPW rgln = (LPW) &lpsl->offset [ coff ]; WORD cbnds = 0; LPBNDS rgbnds = NULL; rgbnds = BuildBounds (coff, rgoff, &cbnds); if (rgbnds != NULL) { SortOffFromBounds (cbnds, rgbnds, coff, rgoff); SortLnFromBounds (cbnds, rgbnds, coff, rgln ); MHFree (rgbnds); } }
int WINAPI SLCAddrFromLine ( HEXE hexeStart, HMOD hmodStart, LSZ lszFileT, WORD line, LPSLP *lplpslp ) { LPSLP lpslp = (LPSLP)NULL; int cslp = 0; HMOD hmod = hmodStart; HEXE hexe = hexeStart; int iPass; char szFileBuf[_MAX_PATH]; LPSTR lszFile; assert(lplpslp); assert(lszFileT); assert(*lszFileT != '\0'); // If the filename is quoted, remove the quotes. if ((*lszFileT == '\"') && (*(lszFileT + _tcslen(lszFileT) - 1) == '\"')) { lszFile = szFileBuf; memcpy(lszFile, _tcsinc(lszFileT), _tcslen(lszFileT) - 2); lszFile[_tcslen(lszFileT)-2] = '\0'; } else { lszFile = lszFileT; } if ((SlCache.cslp != -1) && (hexeStart == SlCache.hexe) && (hmodStart == SlCache.hmod) && (line == SlCache.line) && (!_tcscmp(lszFile, SlCache.szFile))) { if ((SlCache.cslp == 0) || !(lpslp = (LPSLP)MHAlloc(sizeof(SLP) * (SlCache.cslp)))) { *lplpslp = NULL; return 0; } assert(SlCache.lpslp != NULL); memcpy(lpslp, SlCache.lpslp, sizeof(SLP) * SlCache.cslp); *lplpslp = lpslp; return SlCache.cslp; } // Two passes, first pass, see if there is an exact match. If there aren't // any exact matches, try to match just the file.ext name. When OMF file // names are fully qualified, we should expect to always find a match on // the first pass. This will help out with the case where there are two // different file.ext's in the exes/dlls loaded. for(iPass = 0; iPass < 2 && !lpslp; ++iPass) { // Loop through all of the exes that we know about. We may want // to change this later while(hexeStart || (hexe = SHGetNextExe(hexe))) { // Extra fast scan to see if the file is in the list of files for the exe if (SLFFileInHexe(hexe, (BOOL)!iPass, lszFile)) { while(hmodStart || (hmod = SHGetNextMod(hexe, hmod))) { LPMDS lpmds = (LPMDS) hmod; short isf; short isfNext = -1; do { isf = isfNext + 1; // Search for the filename in the current module isfNext = IsfFromName((BOOL)!iPass, isf, lszFile, lpmds); if (isfNext != -1) { HSF hsf; SHOFF cb; ADDR addr; WORD iSeg = 0; WORD iEntry = 0; hsf = (HSF)GetLpsfFromIndex( (LPSM) HstFromLpmds(lpmds), isfNext ); // Reuse the original version. Since we have gotten our // own hsf, we know that we will get the correct line // number table while(SLFLineToAddrExtended(hsf, line, &iSeg, &iEntry, &addr, &cb, NULL)) { // This could be smarter to allocate blocks, but the // regular case will be that this will only happen // once rather than multiple times, so just eat up // a little CPU for simplicity if (lpslp) { lpslp = (LPSLP)MHRealloc(lpslp, sizeof(SLP) * (cslp + 1)); } else { lpslp = (LPSLP)MHAlloc(sizeof(SLP)); } // Additional check to see that the allocation // actually succeeded before copying the data if (lpslp) { lpslp[ cslp ].cb = cb; lpslp[ cslp ].addr = addr; ++cslp; } } } } while(isfNext != -1); // If a module is specified, then DON'T loop through the rest of // the modules if (hmodStart) { break; } } } // If a module is specified, DON'T loop through any of the remaining // modules or exes. Also, if an exe is specified, don't go through // any mor exes either if (hmodStart || hexeStart) { break; } } } *lplpslp = lpslp; // Only free up if we need to if (SlCache.cslp < cslp) { if (SlCache.lpslp) { MHFree(SlCache.lpslp); } SlCache.lpslp = (LPSLP)MHAlloc(sizeof(SLP) * cslp); if (SlCache.lpslp == NULL) { return(0); } } if (cslp) { memcpy(SlCache.lpslp, lpslp, sizeof(SLP) * cslp); } _tcscpy(SlCache.szFile, lszFile); SlCache.hexe = hexeStart; SlCache.hmod = hmodStart; SlCache.line = line; SlCache.cslp = cslp; return cslp; }
void ProcessSegmentLoadEvent( DEBUG_EVENT64 * pde, HTHDX hthdx ) /*++ Routine Description: This function takes care of dealing with segment load events from the wow system. These come in as exceptions and are translated to segment load events in ProcessDebugEvent. Arguments: pde - Supplies a pointer to the modified debug event hthdx - Supplies the handle to the thread of the debug event Return Value: None. --*/ { #if defined(i386) && !defined(WIN32S) PDWORDLONG lpdw = &pde->u.Exception.ExceptionRecord.ExceptionInformation[0]; int mode = LOWORD( (DWORD)lpdw[0] ); int cb; int cbRead; int b; char * lpb; WORD packetType = tlfDebugPacket; HEMI hemi; HPRCX hprcx = hthdx->hprc; int idx; SEGMENT_NOTE sn; ADDR addr; EXPECTED_EVENT * pee; DWORD eventCode; DWORD subClass; LDT_ENTRY ldt; BREAKPOINT *bp; DeWow = *pde; if ( !FVDMInitDone ) { HANDLE hmodVDM; hmodVDM = LoadLibrary("VDMDBG.DLL"); if ( hmodVDM != (HANDLE)NULL ) { FVDMActive = TRUE; pfnVDMProcessException = (VDMPROCESSEXCEPTIONPROC) GetProcAddress( hmodVDM, "VDMProcessException" ); pfnVDMGetPointer = (VDMGETPOINTERPROC) GetProcAddress( hmodVDM, "VDMGetPointer" ); pfnVDMGetThreadSelectorEntry = (VDMGETTHREADSELECTORENTRYPROC) GetProcAddress( hmodVDM, "VDMGetThreadSelectorEntry" ); pfnVDMGetThreadContext = (VDMGETCONTEXTPROC) GetProcAddress( hmodVDM, "VDMGetContext" ); pfnVDMSetThreadContext = (VDMSETCONTEXTPROC) GetProcAddress( hmodVDM, "VDMSetContext" ); pfnVDMGetSelectorModule = (VDMGETSELECTORMODULEPROC) GetProcAddress( hmodVDM, "VDMGetSelectorModule" ); pfnVDMEnumProcessWOW = (VDMENUMPROCESSWOWPROC) GetProcAddress( hmodVDM, "VDMEnumProcessWOW" ); } else { DMPrintShellMsg( _T("LoadLibrary(VDMDBG.DLL) failed\n")); } FVDMInitDone = TRUE; } if ( !FVDMActive ) { return; } else { DebugEvent64To32(pde, &DeWow32); (*pfnVDMProcessException)((LPDEBUG_EVENT)&DeWow32); DebugEvent32To64(&DeWow32, pde); } hthdx->fWowEvent = TRUE; switch ( mode ) { /* * SEG LOAD: * * LOWORD(lpdw[0]) --- DBG_SEGLOAD * HIWORD(lpdw[0]) --- Unused * LOWORD(lpdw[1]) --- Unused * HIWORD(lpdw[1]) --- Unused * lpdw[2] --- pointer to SEGMENT_NOTE structure * lpdw[3] --- Reserved */ case DBG_SEGLOAD: lpb = (char *) lpdw[2]; b = DbgReadMemory(hprcx, (UINT_PTR)lpb, &sn, sizeof(sn), &cbRead); if ((b == 0) || (cbRead != sizeof(sn))) { b = GetLastError(); AddQueue( QT_CONTINUE_DEBUG_EVENT, hthdx->hprc->pid, hthdx->tid, DBG_CONTINUE, 0); //hthdx->tstate &= ~(ts_stopped|ts_first|ts_second); //hthdx->tstate |= ts_running; hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate & ~(ts_stopped|ts_first|ts_second)); hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate | (ts_running)); return; } if (sn.FileName[0] == 0) { AddQueue( QT_CONTINUE_DEBUG_EVENT, hthdx->hprc->pid, hthdx->tid, DBG_CONTINUE, 0); //hthdx->tstate &= ~(ts_stopped|ts_first|ts_second); //hthdx->tstate |= ts_running; hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate & ~(ts_stopped|ts_first|ts_second)); hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate | (ts_running)); return; } cb = _tcslen(sn.FileName)+1; idx = LookupDllName(hprcx, sn.FileName); if ( idx != -1 ) { if (hprcx->rgDllList[idx].fReal) { // // Changing from real to protected mode. We don't // support this, so we'll throw away what we have // and start from scratch. // WORD w = (WORD)idx; DMSendDebugPacket(dbceModFree16, hprcx->hpid, hthdx->htid, sizeof(WORD), &w ); RemoveDllName( hprcx, idx ); idx = -1; } } if (idx == -1) { LPMODULELOAD lpmdl; cb = cb + sizeof(MODULELOAD) + (sn.Segment+1)*sizeof(OBJD); lpmdl = (LPMODULELOAD) MHAlloc(cb); lpmdl->cobj = sn.Segment+1; lpmdl->rgobjd[sn.Segment].wSel = sn.Selector1; lpmdl->rgobjd[sn.Segment].cb = (DWORD) -1; lpmdl->rgobjd[sn.Segment].wPad = 1; lpmdl->mte = InsertDllName(hprcx, sn.FileName); _tcscpy((char *) &lpmdl->rgobjd[lpmdl->cobj], sn.FileName); lpmdl->fRealMode = FALSE; lpmdl->fFlatMode = FALSE; lpmdl->fOffset32 = FALSE; DMSendRequestReply(dbcModLoad, hprcx->hpid, hthdx->htid, cb, lpmdl, sizeof(HEMI), &hemi ); hemi = *((HEMI *) abEMReplyBuf); MHFree(lpmdl); AddQueue( QT_CONTINUE_DEBUG_EVENT, hthdx->hprc->pid, hthdx->tid, DBG_CONTINUE, 0); //hthdx->tstate &= ~(ts_stopped|ts_first|ts_second); //hthdx->tstate |= ts_running; hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate & ~(ts_stopped|ts_first|ts_second)); hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate | (ts_running)); } else { SLI sli; sli.wSelector = sn.Selector1; sli.wSegNo = sn.Segment; sli.mte = idx; DMSendDebugPacket(dbceSegLoad, hprcx->hpid, hthdx->htid, sizeof(SLI), &sli ); } break; /* * SEGMOVE: * * This event will be triggered if a selector number * is to be changed. * * LOWORD( lpdw[0] ) - SEGMOVE * LOWORD( lpdw[1] ) - old selector number * HIWORD( lpdw[1] ) - new selector number */ case DBG_SEGMOVE: lpb = (char *) lpdw[2]; b = DbgReadMemory(hprcx, (UINT_PTR)lpb, &sn, sizeof(sn), &cbRead); if ((b == 0) || (cbRead != sizeof(sn))) { b = GetLastError(); AddQueue( QT_CONTINUE_DEBUG_EVENT, hthdx->hprc->pid, hthdx->tid, DBG_CONTINUE, 0); //hthdx->tstate &= ~(ts_stopped|ts_first|ts_second); //hthdx->tstate |= ts_running; hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate & ~(ts_stopped|ts_first|ts_second)); hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate | (ts_running)); return; } if (sn.FileName[0] == 0) { AddQueue( QT_CONTINUE_DEBUG_EVENT, hthdx->hprc->pid, hthdx->tid, DBG_CONTINUE, 0); //hthdx->tstate &= ~(ts_stopped|ts_first|ts_second); //hthdx->tstate |= ts_running; hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate & ~(ts_stopped|ts_first|ts_second)); hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate | (ts_running)); return; } cb = _tcslen(sn.FileName)+1; idx = LookupDllName(hprcx, sn.FileName); if ( idx != -1 ) { SLI sli; assert( sn.Selector1 == 0 ); sli.wSelector = sn.Selector2; sli.wSegNo = sn.Segment; sli.mte = idx; DMSendDebugPacket(dbceSegMove, hprcx->hpid, hthdx->htid, sizeof(SLI), &sli ); } AddQueue( QT_CONTINUE_DEBUG_EVENT, hthdx->hprc->pid, hthdx->tid, DBG_CONTINUE, 0); //hthdx->tstate &= ~(ts_stopped|ts_first|ts_second); //hthdx->tstate |= ts_running; hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate & ~(ts_stopped|ts_first|ts_second)); hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate | (ts_running)); break; /* * SEGFREE: * * This event is triggered if a selector is freed * * LOWORD( lpdw[0] ) - SEGFREE * HIWORD( lpdw[0] ) - fBPRelease * LOWORD( lpdw[1] ) - selector to be freed */ case DBG_SEGFREE: AddQueue( QT_CONTINUE_DEBUG_EVENT, hthdx->hprc->pid, hthdx->tid, DBG_CONTINUE, 0); //hthdx->tstate &= ~(ts_stopped|ts_first|ts_second); //hthdx->tstate |= ts_running; hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate & ~(ts_stopped|ts_first|ts_second)); hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate | (ts_running)); break; /* * MODLOAD: * * This event is triggered when a new DLL is loaded * * LOWORD( lpdw[0] ) - MODLOAD * HIWORD( lpdw[0] ) - length of module name * HIWORD( lpdw[1] ) - selector * lpdw[2] - address of module name * lpdw[3] - image length * */ case DBG_MODLOAD: lpb = (char *) lpdw[2]; b = DbgReadMemory(hprcx, (UINT_PTR)lpb, &sn, sizeof(sn), &cbRead); if ((b == 0) || (cbRead != sizeof(sn))) { b = GetLastError(); AddQueue( QT_CONTINUE_DEBUG_EVENT, hthdx->hprc->pid, hthdx->tid, DBG_CONTINUE, 0); //hthdx->tstate &= ~(ts_stopped|ts_first|ts_second); //hthdx->tstate |= ts_running; hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate & ~(ts_stopped|ts_first|ts_second)); hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate | (ts_running)); return; } if (sn.FileName[0] == 0) { AddQueue( QT_CONTINUE_DEBUG_EVENT, hthdx->hprc->pid, hthdx->tid, DBG_CONTINUE, 0); //hthdx->tstate &= ~(ts_stopped|ts_first|ts_second); //hthdx->tstate |= ts_running; hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate & ~(ts_stopped|ts_first|ts_second)); hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate | (ts_running)); return; } cb = _tcslen(sn.FileName)+1; idx = LookupDllName(hprcx, sn.FileName); if (idx == -1) { LPMODULELOAD lpmdl; cb = cb + sizeof(MODULELOAD); lpmdl = (LPMODULELOAD) MHAlloc(cb); lpmdl->cobj = 0; lpmdl->mte = InsertDllName(hprcx, sn.FileName); idx = LookupDllName(hprcx, sn.FileName); if ( idx != -1 ) { hprcx->rgDllList[idx].fReal = TRUE; } _tcscpy((char *) &lpmdl->rgobjd[lpmdl->cobj], sn.FileName); lpmdl->StartingSegment = sn.Segment; lpmdl->fRealMode = TRUE; lpmdl->fFlatMode = FALSE; lpmdl->fOffset32 = FALSE; DMSendRequestReply(dbcModLoad, hprcx->hpid, hthdx->htid, cb, lpmdl, sizeof(HEMI), &hemi ); MHFree(lpmdl); } AddQueue( QT_CONTINUE_DEBUG_EVENT, hthdx->hprc->pid, hthdx->tid, DBG_CONTINUE, 0); //hthdx->tstate &= ~(ts_stopped|ts_first|ts_second); //hthdx->tstate |= ts_running; hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate & ~(ts_stopped|ts_first|ts_second)); hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate | (ts_running)); break; /* * MODFREE: * * This event is triggered when a DLL is unloaded * * LOWORD( lpdw[0] ) - MODFREE */ case DBG_MODFREE: lpb = (char *) lpdw[2]; b = DbgReadMemory(hprcx, (UINT_PTR)lpb, &sn, sizeof(sn), &cbRead); if ((b == 0) || (cbRead != sizeof(sn))) { b = GetLastError(); AddQueue( QT_CONTINUE_DEBUG_EVENT, hthdx->hprc->pid, hthdx->tid, DBG_CONTINUE, 0); //hthdx->tstate &= ~(ts_stopped|ts_first|ts_second); //hthdx->tstate |= ts_running; hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate & ~(ts_stopped|ts_first|ts_second)); hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate | (ts_running)); return; } if (sn.FileName[0] == 0) { AddQueue( QT_CONTINUE_DEBUG_EVENT, hthdx->hprc->pid, hthdx->tid, DBG_CONTINUE, 0); //hthdx->tstate &= ~(ts_stopped|ts_first|ts_second); //hthdx->tstate |= ts_running; hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate & ~(ts_stopped|ts_first|ts_second)); hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate | (ts_running)); return; } cb = _tcslen(sn.FileName)+1; idx = LookupDllName(hprcx, sn.FileName); if (idx != -1) { WORD w = (WORD)idx; DMSendDebugPacket(dbceModFree16, hprcx->hpid, hthdx->htid, sizeof(WORD), &w ); RemoveDllName( hprcx, idx ); } AddQueue( QT_CONTINUE_DEBUG_EVENT, hthdx->hprc->pid, hthdx->tid, DBG_CONTINUE, 0); //hthdx->tstate &= ~(ts_stopped|ts_first|ts_second); //hthdx->tstate |= ts_running; hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate & ~(ts_stopped|ts_first|ts_second)); hthdx->tstate = (TSTATEX)((DWORD)hthdx->tstate | (ts_running)); break; /* * Int 01h break; */ case DBG_SINGLESTEP: hthdx->context.ContextFlags = VDMCONTEXT_FULL; (*pfnVDMGetThreadContext)(hthdx->hprc->rwHand, hthdx->rwHand, &hthdx->context); eventCode = EXCEPTION_DEBUG_EVENT; pde->dwDebugEventCode = EXCEPTION_DEBUG_EVENT; pde->u.Exception.ExceptionRecord.ExceptionCode = subClass = (DWORD)EXCEPTION_SINGLE_STEP; /* * They are not clearing the trace bit */ hthdx->context.EFlags &= ~TF_BIT_MASK; hthdx->fContextDirty = TRUE; AddrInit(&addr, 0, (SEGMENT) hthdx->context.SegCs, SE32To64( hthdx->context.Eip ), FALSE, FALSE, FALSE, FALSE ); bp = FindBP(hthdx->hprc, hthdx, bptpExec, (BPNS)-1, &addr, FALSE); if ( bp ) { SetBPFlag( hthdx, bp ); } goto dispatch; case DBG_TASKSTART: hthdx->context.ContextFlags = VDMCONTEXT_FULL; (*pfnVDMGetThreadContext)(hthdx->hprc->rwHand, hthdx->rwHand, &hthdx->context); eventCode = pde->dwDebugEventCode = ENTRYPOINT_DEBUG_EVENT; goto dispatch; case DBG_TASKSTOP: case DBG_DLLSTART: case DBG_DLLSTOP: case DBG_ATTACH: AddQueue( QT_CONTINUE_DEBUG_EVENT, hthdx->hprc->pid, hthdx->tid, DBG_CONTINUE, 0); hthdx->tstate &= ~(ts_stopped|ts_first|ts_second); hthdx->tstate |= ts_running; break; /* * Int 03h break * * LOWORD(lpdw[0]) --- BREAKPOINT * HIWORD(lpdw[0]) --- Protect Mode */ case DBG_BREAK: hthdx->context.ContextFlags = VDMCONTEXT_FULL; (*pfnVDMGetThreadContext)(hthdx->hprc->rwHand, hthdx->rwHand, &hthdx->context); Set_PC(hthdx, PC(hthdx) - 1); hthdx->fContextDirty = TRUE; eventCode = pde->dwDebugEventCode = BREAKPOINT_DEBUG_EVENT; // NOTENOTE --- jimsch -- assuming only 0xcc not 0xcd 0x3 breakpoints AddrInit(&addr, 0, (SEGMENT) hthdx->context.SegCs, SE32To64( hthdx->context.Eip ), FALSE, FALSE, FALSE, FALSE ); bp = FindBP(hthdx->hprc, hthdx, bptpExec, (BPNS)-1, &addr, FALSE); if ( bp && bp->isStep ) { eventCode = EXCEPTION_DEBUG_EVENT; pde->dwDebugEventCode = EXCEPTION_DEBUG_EVENT; pde->u.Exception.ExceptionRecord.ExceptionCode = subClass = (DWORD)EXCEPTION_SINGLE_STEP; RemoveBP(bp); } else { if ( bp ) { SetBPFlag( hthdx, bp ); } pde->u.Exception.ExceptionRecord.ExceptionCode = subClass = (DWORD)bp; } pde->u.Exception.ExceptionRecord.ExceptionAddress = PC(hthdx); dispatch: hthdx->fAddrIsReal = FALSE; hthdx->fAddrIsFlat = FALSE; DebugEvent64To32(pde, &DeWow32); if ((*pfnVDMGetThreadSelectorEntry)(&DeWow32, hthdx->rwHand, (WORD) hthdx->context.SegCs, &ldt)) { if (ldt.HighWord.Bits.Default_Big) { hthdx->fAddrOff32 = TRUE; } else { hthdx->fAddrOff32 = FALSE; } } else { hthdx->fAddrOff32 = FALSE; } /* * Check if this debug event was expected */ pee = PeeIsEventExpected(hthdx, eventCode, subClass, TRUE); /* * If it wasn't, run the standard handler with * notifications going to the execution model */ assert((0 < eventCode) && (eventCode < MAX_EVENT_CODE)); if (pee == NULL) { if ((hthdx != NULL) && (hthdx->tstate & ts_funceval)) { RgfnFuncEventDispatch[eventCode-EXCEPTION_DEBUG_EVENT](pde, hthdx); } else { DebugDispatchTable[eventCode-EXCEPTION_DEBUG_EVENT](pde,hthdx); } return; } /* * If it was expected then call the action * function if one was specified */ if (pee->action) { (pee->action)(pde, hthdx, 0, pee->lparam); } /* * And call the notifier if one was specified */ if (pee->notifier) { METHOD *nm = pee->notifier; (nm->notifyFunction)(pde, hthdx, 0, nm->lparam); } free(pee); break; #if 0 // why is this here?? case DBG_DIVOVERFLOW: pde->dwDebugEventCode = 3; goto fault_occured; case DBG_INSTRFAULT: pde->dwDebugEventCode = 1; goto fault_occured; #endif case DBG_DIVOVERFLOW: case DBG_INSTRFAULT: case DBG_GPFAULT: pde->dwDebugEventCode = EXCEPTION_DEBUG_EVENT; #if 0 // why is this here?? fault_occured: #endif hthdx->context.ContextFlags = VDMCONTEXT_FULL; (*pfnVDMGetThreadContext)(hthdx->hprc->rwHand, hthdx->rwHand, &hthdx->context); pde->u.Exception.ExceptionRecord.ExceptionCode = 13; hthdx->fAddrIsReal = FALSE; hthdx->fAddrIsFlat = FALSE; DebugEvent64To32(pde, &DeWow32); if ((*pfnVDMGetThreadSelectorEntry)(&DeWow32, hthdx->rwHand, (WORD) hthdx->context.SegCs, &ldt)) { if (ldt.HighWord.Bits.Default_Big) { hthdx->fAddrOff32 = TRUE; } else { hthdx->fAddrOff32 = FALSE; } } else { hthdx->fAddrOff32 = FALSE; } ProcessExceptionEvent(pde, hthdx); break; default: AddQueue( QT_CONTINUE_DEBUG_EVENT, hthdx->hprc->pid, hthdx->tid, DBG_CONTINUE, 0); hthdx->tstate &= ~(ts_stopped|ts_first|ts_second); hthdx->tstate |= ts_running; break; } #endif // i386 && !Win32S return; } /* ProcessSegmentLoadEvent() */
BOOL FExecTrojan(HTHDX pthd, TROJAN *ptrj, LPB rgbBuf, UINT cbBuf, CONTEXT *pcxt) { BOOL fOK = FALSE; CONTEXT cxtOld; int i; UINT ib = 0; LPB lpbOld = NULL; BOOL fRestoreBuf = FALSE; DWORD cbGot; DEBUG_EVENT de; HPRCX hprc = pthd->hprc; HTHDX hthdCurr; // if we do a GetContext here on NT, the EIP points to one past the initial int 3 // so we use the cached value instead cxtOld = pthd->context; if (IsChicago()) { // // On Chicago, we cannot write Trojans into the stack memory space, // because Chicago trashes that memory when we return control to // the debuggee. So we instead try to write the Trojan to the // current EIP. If that fails, we'll return FALSE. // uoffTrjBase = pthd->context.Eip; lpbOld = (LPB)MHAlloc(cbBuf); if (!lpbOld) { goto end; } if (!ReadProcessMemory(pthd->hprc->rwHand, (LPCVOID)uoffTrjBase, lpbOld, cbBuf, &cbGot) || (cbGot!=cbBuf) ) { goto end; } fRestoreBuf = TRUE; } else { // // On NT, we'll write the Trojan into the stack memory space. // We'll readjust the stack pointer to point just before the // Trojan. // Stack before writing Trojan: // +-------------------------------------------------------+ // | | user stack data | // +-------------------------------------------------------+ // esp // // Stack after writing Trojan: // +-------------------------------------------------------+ // | stack used by trojan | trojan | user stack data | // +-------------------------------------------------------+ // esp // // Round up to DWORD. pthd->context.Esp -= ((cbBuf + 3) / 4) * 4; uoffTrjBase = pthd->context.Eip = pthd->context.Esp; } clbl = clblref = 0; for (i=0; ptrj[i].pfn; ++i) { if (!ptrj[i].pfn(ptrj[i].lsz, rgbBuf, &ib)) goto end; } assert(ib <= cbBuf); // make sure we didn't overflow // Write the trojan code to remote memory if (!WriteProcessMemory(pthd->hprc->rwHand, (LPVOID)uoffTrjBase, rgbBuf, cbBuf, &cbGot) || (cbGot!=cbBuf)) { goto end; } // set the new EIP/ESP VERIFY(SetThreadContext( pthd->rwHand, &pthd->context )); // Freeze all threads except our one for (hthdCurr = hprc->hthdChild; hthdCurr != NULL; hthdCurr = hthdCurr->nextSibling) { if (hthdCurr != pthd) { if (SuspendThread(hthdCurr->rwHand) == -1L) { ; // Internal error; } } } // let the trojan run, will hit int 3 before sending create thread (we hope!!) VERIFY(ContinueDebugEvent(pthd->hprc->pid, pthd->tid, DBG_CONTINUE)); if (!WaitForDebugEvent(&de, INFINITE)) { assert( !"WaitForDebugEvent failed during trojan" ); } else { assert(de.dwDebugEventCode == EXCEPTION_DEBUG_EVENT); if (de.u.Exception.ExceptionRecord.ExceptionCode != EXCEPTION_BREAKPOINT) { #if DEBUG // didn't hit the bp - get some other info to see what is going on CONTEXT cxt; DWORD ip; BYTE buf[20]; GetThreadContext(pthd->rwHand, &pthd->context); ip = cxt.Eip; ReadProcessMemory( pthd->hprc->rwHand, (LPCVOID)(ip-10), buf, sizeof(buf), &cbGot ); #endif assert( !"Trojan code got unexpected event" ); } // Get eax VERIFY(GetThreadContext(pthd->rwHand, &pthd->context)); *pcxt = pthd->context; } /* Resume all threads except this one */ for (hthdCurr = hprc->hthdChild; hthdCurr != NULL; hthdCurr = hthdCurr->nextSibling) { if (hthdCurr != pthd) { if (ResumeThread(hthdCurr->rwHand) == -1L) { assert(FALSE); // Internal error; } } } // Read back the new contents of the trojan to get return values etc if (!ReadProcessMemory(pthd->hprc->rwHand, (LPCVOID)uoffTrjBase, rgbBuf, cbBuf, &cbGot) || (cbGot!=cbBuf) ) { goto end; } fOK = TRUE; end: // Restore old memory if (fRestoreBuf) { assert(lpbOld); VERIFY(WriteProcessMemory(pthd->hprc->rwHand, (LPVOID)uoffTrjBase, lpbOld, cbBuf, &cbGot) && (cbGot == cbBuf)); } // Restore old registers always (after memory in case context is stored there) pthd->context = cxtOld; VERIFY(SetThreadContext(pthd->rwHand, &pthd->context)); if (lpbOld) { MHFree(lpbOld); } return fOK; }