void *readTask(FILE *inputFile){ Task *task = createTask(); TaskIdList *list = NULL; int endedTasks=-1, metaSize=-1, taskState=-1, id=-1; char *metadata = NULL; READ_BEGIN(inputFile); list = (TaskIdList *)readTaskIdList(inputFile); setTaskDependsOnMe(task, list); taskIdListDestroy(list); list = (TaskIdList *)readTaskIdList(inputFile); setTaskMyDeps(task, list); taskIdListDestroy(list); hashIntVoidDeserialize(inputFile, task->children); // make the children point to its mother HashIntVoidIterator *it = createHashIntVoidIterator(task->children, 0); PosHandlerIntVoid pos = hashIntVoidIteratorNext(it, task->children); while (pos != NULL) { Task *child = posGetValue(pos); child->mother = task; pos = hashIntVoidIteratorNext(it, task->children); } hashIntVoidIteratorDestroy(it, task->children); READ_NUM("id", id); setTaskId(task, id); READ_NUM("endedTasks", endedTasks); setTaskEndedTasks(task, endedTasks); READ_NUM("metaSize", metaSize); if (metaSize > 0) { metadata = malloc(metaSize); } else { metadata = NULL; } READ_BYTES(inputFile, metadata, metaSize); setTaskMetadata(task, metadata, metaSize); if(metadata != NULL){ free(metadata); } READ_NUM("taskState", taskState); setTaskState(task, taskState); DataSpace* dataSpace = createDataSpace(); readDataSpace(inputFile, dataSpace); setTaskDataSpace(task, dataSpace); READ_END return (void *)task; }
bool PCProcess::hideDebugger() { Dyninst::ProcControlAPI::Thread::const_ptr threadPtr_ = pcProc_->threads().getInitialThread(); if (!threadPtr_) return false; Address tibPtr = threadPtr_->getThreadInfoBlockAddr(); if (!tibPtr) { return false; } // read in address of PEB unsigned int pebPtr; if (!readDataSpace((void*)(tibPtr+48), getAddressWidth(), (void*)&pebPtr, false)) { fprintf(stderr, "%s[%d] Failed to read address of Process Environment " "Block at 0x%x, which is TIB + 0x30\n", FILE__,__LINE__,tibPtr+48); return false; } // patch up the processBeingDebugged flag in the PEB unsigned char flag; if (!readDataSpace((void*)(pebPtr+2), 1, (void*)&flag, true)) return false; if (flag) { flag = 0; if (!writeDataSpace((void*)(pebPtr+2), 1, (void*)&flag)) return false; } //while we're at it, clear the NtGlobalFlag if (!readDataSpace((void*)(pebPtr+0x68), 1, (void*)&flag, true)) return false; if (flag) { flag = flag & 0x8f; if (!writeDataSpace((void*)(pebPtr+0x68), 1, (void*)&flag)) return false; } // clear the heap flags in the PEB unsigned int heapBase; unsigned int flagWord; if (!readDataSpace((void*)(pebPtr+0x18), 4, (void*)&heapBase, true)) return false; // clear the flags in the heap itself if (!readDataSpace((void*)(heapBase+0x0c), 4, (void*)&flagWord, true)) return false; flagWord = flagWord & (~0x50000062); if (!writeDataSpace((void*)(heapBase+0x0c), 4, (void*)&flagWord)) return false; if (!readDataSpace((void*)(heapBase+0x10), 4, (void*)&flagWord, true)) return false; flagWord = flagWord & (~0x40000060); if (!writeDataSpace((void*)(heapBase+0x10), 4, (void*)&flagWord)) return false; return true; }
bool process::loadDYNINSTlib() { /* Look for a function we can hijack to forcibly load dyninstapi_rt. This is effectively an inferior RPC with the caveat that we're overwriting code instead of allocating memory from the RT heap. (So 'hijack' doesn't mean quite what you might think.) */ Address codeBase = findFunctionToHijack(this); if( !codeBase ) { return false; } /* glibc 2.3.4 and higher adds a fourth parameter to _dl_open(). While we could probably get away with treating the three and four -argument functions the same, check the version anyway, since we'll probably need to later. */ bool useFourArguments = true; Symbol libcVersionSymbol; if( getSymbolInfo( "__libc_version", libcVersionSymbol ) ) { char libcVersion[ sizeof( int ) * libcVersionSymbol.size() + 1 ]; libcVersion[ sizeof( int ) * libcVersionSymbol.size() ] = '\0'; if( ! readDataSpace( (void *) libcVersionSymbol.addr(), libcVersionSymbol.size(), libcVersion, true ) ) { fprintf( stderr, "%s[%d]: warning, failed to read libc version, assuming 2.3.4+\n", __FILE__, __LINE__ ); } else { startup_printf( "%s[%d]: libcVersion: %s\n", __FILE__, __LINE__, libcVersion ); /* We could potentially add a sanity check here to make sure we're looking at 2.3.x. */ int microVersion = ((int)libcVersion[4]) - ((int)'0'); if( microVersion <= 3 ) { useFourArguments = false; } } /* end if we read the version symbol */ } /* end if we found the version symbol */ if( useFourArguments ) { startup_printf( "%s[%d]: using four arguments.\n", __FILE__, __LINE__ ); } /* Fetch the name of the run-time library. */ const char DyninstEnvVar[]="DYNINSTAPI_RT_LIB"; if( ! dyninstRT_name.length() ) { // we didn't get anything on the command line if (getenv(DyninstEnvVar) != NULL) { dyninstRT_name = getenv(DyninstEnvVar); } else { pdstring msg = pdstring( "Environment variable " + pdstring( DyninstEnvVar ) + " has not been defined for process " ) + pdstring( getPid() ); showErrorCallback(101, msg); return false; } /* end if enviromental variable not found */ } /* end enviromental variable extraction */ /* Save the (main thread's) current PC.*/ savedPC = getRepresentativeLWP()->getActiveFrame().getPC(); /* _dl_open() takes three arguments: a pointer to the library name, the DLOPEN_MODE, and the return address of the current frame (that is, the location of the SIGILL-generating bundle we'll use to handleIfDueToDyninstLib()). We construct the first here. */ /* Write the string to entry, and then move the PC to the next bundle. */ codeGen gen(BYTES_TO_SAVE); Address dyninstlib_addr = gen.used() + codeBase; gen.copy(dyninstRT_name.c_str(), dyninstRT_name.length()+1); Address dlopencall_addr = gen.used() + codeBase; /* At this point, we use the generic iRPC headers and trailers around the call to _dl_open. (Note that pre-1.35 versions of this file had a simpler mechanism well-suited to boot- strapping a new port. The current complexity is to handle the attach() case, where we don't know if execution was stopped at the entry the entry point to a function. */ bool ok = theRpcMgr->emitInferiorRPCheader(gen); if( ! ok ) { return false; } /* Generate the call to _dl_open with a large dummy constant as the the third argument to make sure we generate the same size code the second time around, with the correct "return address." (dyninstlib_brk_addr) */ // As a quick note, we want to "return" to the beginning of the restore // segment, not dyninstlib_brk_addr (or we skip all the restores). // Of course, we're not sure what this addr represents.... pdvector< AstNode * > dlOpenArguments( 4 ); AstNode * dlOpenCall; dlOpenArguments[ 0 ] = new AstNode( AstNode::Constant, (void *)dyninstlib_addr ); dlOpenArguments[ 1 ] = new AstNode( AstNode::Constant, (void *)DLOPEN_MODE ); dlOpenArguments[ 2 ] = new AstNode( AstNode::Constant, (void *)0xFFFFFFFFFFFFFFFF ); if( useFourArguments ) { /* I derived the -2 as follows: from dlfcn/dlopen.c in the glibc sources, line 59, we find the call to _dl_open(), whose last argument is 'args->file == NULL ? LM_ID_BASE : NS'. Since the filename we pass in is non-null, this means we (would) pass in NS, which is defined to be __LM_ID_CALLER in the same file, line 48. (Since glibc must be shared for us to be calling _dl_open(), we fall into the second case of the #ifdef.) __LM_ID_CALLER is defined in include/dlfcn.h, where it has the value -2. */ dlOpenArguments[ 3 ] = new AstNode( AstNode::Constant, (void *)(long unsigned int)-2 ); } dlOpenCall = new AstNode( "_dl_open", dlOpenArguments ); /* Remember where we originally generated the call. */ codeBufIndex_t index = gen.getIndex(); /* emitInferiorRPCheader() configures (the global) registerSpace for us. */ dlOpenCall->generateCode( this, regSpace, gen, true, true ); // Okay, we're done with the generation, and we know where we'll be. // Go back and regenerate it Address dlopenRet = codeBase + gen.used(); gen.setIndex(index); /* Clean up the reference counts before regenerating. */ removeAst( dlOpenCall ); removeAst( dlOpenArguments[ 2 ] ); dlOpenArguments[ 2 ] = new AstNode( AstNode::Constant, (void *)dlopenRet ); dlOpenCall = new AstNode( "_dl_open", dlOpenArguments ); /* Regenerate the call at the same original location with the correct constants. */ dlOpenCall->generateCode( this, regSpace, gen, true, true ); /* Clean up the reference counting. */ removeAst( dlOpenCall ); removeAst( dlOpenArguments[ 0 ] ); removeAst( dlOpenArguments[ 1 ] ); removeAst( dlOpenArguments[ 2 ] ); if( useFourArguments ) { removeAst( dlOpenArguments[ 3 ] ); } // Okay, that was fun. Now restore. And trap. And stuff. unsigned breakOffset, resultOffset, justAfterResultOffset; ok = theRpcMgr->emitInferiorRPCtrailer(gen, breakOffset, false, resultOffset, justAfterResultOffset ); if( ! ok ) { return false; } /* Let everyone else know that we're expecting a SIGILL. */ dyninstlib_brk_addr = codeBase + breakOffset; assert(gen.used() < BYTES_TO_SAVE); /* Save the function we're going to hijack. */ InsnAddr iAddr = InsnAddr::generateFromAlignedDataAddress( codeBase, this ); /* We need to save the whole buffer, because we don't know how big gen is when we do the restore. This could be made more efficient by storing gen.used() somewhere. */ iAddr.saveBundlesTo( savedCodeBuffer, sizeof( savedCodeBuffer ) / 16 ); /* Write the call into the mutatee. */ InsnAddr jAddr = InsnAddr::generateFromAlignedDataAddress( codeBase, this ); jAddr.writeBundlesFrom( (unsigned char *)gen.start_ptr(), gen.used() / 16 ); /* Now that we know where the code will start, move the (main thread's) PC there. */ getRepresentativeLWP()->changePC( dlopencall_addr, NULL ); /* Let them know we're working on it. */ setBootstrapState( loadingRT_bs ); return true; } /* end dlopenDYNINSTlib() */
mapped_object* PCProcess::createObjectNoFile(Address addr) { Address closestObjEnd = 0; for (unsigned i = 0; i < mapped_objects.size(); i++) { if (addr >= mapped_objects[i]->codeAbs() && addr < (mapped_objects[i]->codeAbs() + mapped_objects[i]->imageSize())) { fprintf(stderr,"createObjectNoFile called for addr %lx, " "matching existing mapped_object %s %s[%d]\n", addr, mapped_objects[i]->fullName().c_str(), FILE__,__LINE__); return mapped_objects[i]; } if (addr >= (mapped_objects[i]->codeAbs() + mapped_objects[i]->imageSize()) && closestObjEnd < (mapped_objects[i]->codeAbs() + mapped_objects[i]->imageSize())) { closestObjEnd = mapped_objects[i]->codeAbs() + mapped_objects[i]->imageSize(); } } Address testRead = 0; // WindowsAPI VirtualQueryEx rounds down to pages size, // so we need to round up first. Address ObjOffset = closestObjEnd % getMemoryPageSize(); if (ObjOffset) { closestObjEnd = closestObjEnd - ObjOffset + getMemoryPageSize(); } if (readDataSpace((void*)addr, getAddressWidth(), &testRead, false)) { // create a module for the region enclosing this address ProcControlAPI::Process::MemoryRegion memRegion; if (!pcProc_->findAllocatedRegionAround(addr, memRegion)) { mal_printf("ERROR: failed to find allocated region for page %lx, %s[%d]\n", addr, FILE__, __LINE__); assert(0); return NULL; } mal_printf("[%lx %lx] is valid region containing %lx and corresponding " "to no object, closest is object ending at %lx %s[%d]\n", memRegion.first, memRegion.second, addr, closestObjEnd, FILE__,__LINE__); // The size of the region returned by VirtualQueryEx is from BaseAddress // to the end, NOT from meminfo.AllocationBase, which is what we want. // BaseAddress is the start address of the page of the address parameter // that is sent to VirtualQueryEx as a parameter Address regionSize = memRegion.second - memRegion.first; // read region into this PCProcess void* rawRegion = malloc(regionSize); if (!readDataSpace((void *)memRegion.first, regionSize, rawRegion, true)) { mal_printf("Error: failed to read memory region [%lx, %lx]\n", memRegion.first, memRegion.second); printSysError(GetLastError()); assert(0); return NULL; } // set up file descriptor char regname[64]; snprintf(regname, 63, "mmap_buffer_%lx_%lx", memRegion.first, memRegion.second); fileDescriptor desc(string(regname), memRegion.first, /* code */ memRegion.first, /* data */ regionSize, /* length */ rawRegion, /* rawPtr */ true); /* shared */ mapped_object *obj = mapped_object::createMappedObject (desc, this, getHybridMode(), false); if (obj != NULL) { obj->setMemoryImg(); //mapped_objects.push_back(obj); addMappedObject(obj); obj->parse_img()->getOrCreateModule( obj->parse_img()->getObject()->getDefaultModule()); return obj; } else { fprintf(stderr,"Failed to create object (that was not backed by a file) at %lx\n", memRegion.first); return NULL; } } return NULL; }