//Adding the ProcessHeaps to the generic Memory Ranges BOOL ProcInfo::addProcessHeapsAndCheckAddress(ADDRINT eip){ BOOL isEipDiscoveredHere = FALSE; W::SIZE_T BytesToAllocate; W::PHANDLE aHeaps; //getting the number of ProcessHeaps W::DWORD NumberOfHeaps = W::GetProcessHeaps(0, NULL); if (NumberOfHeaps == 0) { MYERRORE("Error in retrieving number of Process Heaps"); return isEipDiscoveredHere; } //Allocating space for the ProcessHeaps Addresses W::SIZETMult(NumberOfHeaps, sizeof(*aHeaps), &BytesToAllocate); aHeaps = (W::PHANDLE)W::HeapAlloc(W::GetProcessHeap(), 0, BytesToAllocate); if ( aHeaps == NULL) { MYERRORE("HeapAlloc failed to allocate space"); return isEipDiscoveredHere; } W::GetProcessHeaps(NumberOfHeaps,aHeaps); //Adding the memory range containing the ProcessHeaps to the genericMemoryRanges for (int i = 0; i < NumberOfHeaps; ++i) { MemoryRange processHeap; if(getMemoryRange((ADDRINT) aHeaps[i],processHeap)){ genericMemoryRanges.push_back(processHeap); if(eip >= processHeap.StartAddress && eip <= processHeap.EndAddress){ isEipDiscoveredHere = TRUE; } } } return isEipDiscoveredHere; }
void ScyllaWrapperInterface::addImportFunctionToDumpReport(string reconstructed_imports_file){ string line; std::ifstream myfile(reconstructed_imports_file); vector<string> imports; vector<ReportObject *> imports_report; int imports_number=0; //parsing the file to extract modules and functions names and populate json objects while (getline(myfile, line)){ try{ imports = Helper::split(line,' '); //the format of the file is "module_name function_name" ReportObject *current_import = new ReportImportedFunction(imports.at(0), imports.at(1)); imports_number++; imports_report.push_back(current_import); }catch (const std::out_of_range& ){ //handle possible missing information inside the file MYERRORE("Problem adding function to the imported function report line: %s",line.c_str()); } } //Saving the information to the report try{ ReportDump& report_dump = Report::getInstance()->getCurrentDump(); report_dump.setImportedFunctions(imports_report); report_dump.setNumberOfImports(imports_number); } catch (const std::out_of_range& ){ MYERRORE("Problem creating ReportImportedFunction report"); } }
UINT32 YaraHeuristic::run(vector<string> paths_to_analyse){ vector<string> global_matched_rules; bool result = false; for(vector<string>::iterator dump_to_analyse = paths_to_analyse.begin(); dump_to_analyse != paths_to_analyse.end(); dump_to_analyse++){ vector<string> cur_matched_rules = analyseYara(*dump_to_analyse); global_matched_rules.insert(global_matched_rules.end(),cur_matched_rules.begin(),cur_matched_rules.end()); } if(!global_matched_rules.empty()){ result = true; } //Saving the information to the report try{ ReportDump& report_dump = Report::getInstance()->getCurrentDump(); ReportObject* yara_heur = new ReportYaraRules(result, global_matched_rules); report_dump.addHeuristic(yara_heur); } catch (const std::out_of_range& ){ MYERRORE("Problem creating ReportYaraRules report"); } return 0; }
/**Lauch external tool ScyllaDumper to dump the process with PID pid scylla: string containing the path to the scyllaDumper executable pid: pid of the process to dump (Current PID if you want to use the Pin Instrumented Binary) curEip: curre **/ UINT32 ScyllaWrapperInterface::launchScyllaDumpAndFix(std::string scylla,int pid, int curEip,std::string outputFile){ MYINFO("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); MYINFO("LAUNCHING SCYLLADUMP AS AN EXTERNAL PROCESS!!"); MYINFO("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); MYINFO("CURR EIP %x",curEip); W::DWORD exitCode; //Creating the string containing the arguments to pass to the ScyllaTest.exe std::stringstream scyllaArgsStream; scyllaArgsStream << scylla << " "; scyllaArgsStream << pid << " "; scyllaArgsStream << std::hex << curEip << " "; scyllaArgsStream << outputFile << " "; std::string scyllaArgs = scyllaArgsStream.str(); //sprintf(scyllaArgs,"%s %d %x %s",scylla,pid,curEip,outputFile); //argv[0] is the name of the program MYINFO("Scylla cmd %s %s",scylla.c_str(),scyllaArgs.c_str()); //Running external Scyllatest.exe executable W::STARTUPINFO si ={0}; W::PROCESS_INFORMATION pi ={0}; si.cb=sizeof(si); if(!W::CreateProcess(scylla.c_str(),(char *)scyllaArgs.c_str(),NULL,NULL,FALSE,0,NULL,NULL,&si,&pi)){ MYERRORE("(INITFUNCTIONCALL)Can't launch Scylla"); return -5; } W::GetExitCodeProcess(pi.hProcess, &exitCode); W::WaitForSingleObject(pi.hProcess,INFINITE); W::CloseHandle(pi.hProcess); W::CloseHandle(pi.hThread); if(!existFile(outputFile)){ MYERRORE("Scylla Can't dump the process"); return exitCode; } MYINFO("Scylla Finished"); return exitCode; }
/**Lauch external tool ScyllaDumper to dump the process with PID pid scylla : string containing the path to the scyllaDumper executable pid : pid of the process to dump (Current PID if you want to use the Pin Instrumented Binary) curEip : current eip of the program outputFile : the name of the dump we want to create tmpDump : name of the temp file call_plugin_falg : specify if a plugin has to be called if the iat-fix fails plugin_full_path : full path to the dll containing the plugin **/ UINT32 ScyllaWrapperInterface::launchScyllaDumpAndFix(int pid, int curEip, std::string outputFile, std::string tmpDump, bool call_plugin_flag, std::string plugin_full_path, std::string reconstructed_imports_file){ std::string scylla = config->getScyllaDumperPath(); W::DWORD exitCode; //Creating the string containing the arguments to pass to the ScyllaTest.exe std::stringstream scyllaArgsStream; scyllaArgsStream << scylla << " "; scyllaArgsStream << pid << " "; scyllaArgsStream << std::hex << curEip << " "; scyllaArgsStream << outputFile << " "; scyllaArgsStream << tmpDump << " "; scyllaArgsStream << reconstructed_imports_file << " "; scyllaArgsStream << call_plugin_flag << " "; scyllaArgsStream << plugin_full_path << " "; std::string scyllaArgs = scyllaArgsStream.str(); MYINFO("Scylla cmd %s %s",scylla.c_str(),scyllaArgs.c_str()); //Running external Scyllatest.exe executable W::STARTUPINFO si ={0}; W::PROCESS_INFORMATION pi ={0}; si.cb=sizeof(si); if(!W::CreateProcess(scylla.c_str(),(char *)scyllaArgs.c_str(),NULL,NULL,FALSE,0,NULL,NULL,&si,&pi)){ MYERRORE("(INITFUNCTIONCALL)Can't launch Scylla"); return -5; } W::GetExitCodeProcess(pi.hProcess, &exitCode); W::WaitForSingleObject(pi.hProcess,INFINITE); W::CloseHandle(pi.hProcess); W::CloseHandle(pi.hThread); if(!Helper::existFile(outputFile)){ MYERRORE("Scylla Can't dump the process"); return exitCode; } if(Helper::existFile(reconstructed_imports_file)){//exist file containing imported functions addImportFunctionToDumpReport(reconstructed_imports_file); } MYINFO("Scylla Finished"); return SCYLLA_SUCCESS_FIX; }
/** Fill the MemoryRange passed as parameter with the startAddress and EndAddress of the memory location in which the address is contained ADDRINT address: address of which we want to retrieve the memory region MemoryRange& range: MemoryRange which will be filled return TRUE if the address belongs to a memory mapped area otherwise return FALSE **/ BOOL ProcInfo::getMemoryRange(ADDRINT address, MemoryRange& range){ W::MEMORY_BASIC_INFORMATION mbi; int numBytes = W::VirtualQuery((W::LPCVOID)address, &mbi, sizeof(mbi)); if(numBytes == 0){ MYERRORE("VirtualQuery failed"); return FALSE; } int start = (int)mbi.BaseAddress; int end = (int)mbi.BaseAddress+ mbi.RegionSize; //get the stack base address by searching the highest address in the allocated memory containing the stack Address if((mbi.State == MEM_COMMIT || mbi.Type == MEM_MAPPED || mbi.Type == MEM_IMAGE || mbi.Type == MEM_PRIVATE) && start <=address && address <= end){ range.StartAddress = start; range.EndAddress = end; return TRUE; } else{ MYERRORE("Address %08x not inside mapped memory from %08x -> %08x or Type/State not correct ",address,start,end); MYINFO("state %08x %08x",mbi.State,mbi.Type); return FALSE; } }
vector<string> YaraHeuristic::analyseYara(string dump_to_analyse){ string yara_rules_path = Config::getInstance()->getYaraRulesPath(); string yara_exe_path = Config::getInstance()->getYaraExePath(); string yara_res_file = Config::getInstance()->getYaraResultPath(); string raw_output = ""; vector<string> matched_rules; W::SECURITY_ATTRIBUTES sa; // Set the bInheritHandle flag so pipe handles are inherited. sa.nLength = sizeof(W::SECURITY_ATTRIBUTES); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL; // Create a pipe for the child process's STDOUT. if ( ! W::CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &sa, 0) ) { MYERRORE("Error creating Pipe for Yara"); return vector<string>(); } // Ensure the read handle to the pipe for STDOUT is not inherited if ( ! W::SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0) ){ MYERRORE("Error creating Pipe for Yara"); return vector<string>(); } W::PROCESS_INFORMATION piResults; if(launchYara(yara_exe_path,yara_rules_path, dump_to_analyse, yara_res_file,&piResults )){ raw_output = ReadFromPipe(piResults); matched_rules = parseYaraOutput(raw_output); //MYINFO("Yara raw output result %s",raw_output.c_str()); } else{ MYERRORE("error launching Yara"); } return matched_rules; }
BOOL YaraHeuristic::launchYara(std::string yara_path, std::string yara_rules_path, std::string yara_input_path,std::string yara_output,W::PROCESS_INFORMATION * piResults){ //string YaraLauncherBat = Config::getInstance()->getBasePath() + YARA_LAUNCHER; //Running external idaPython script W::STARTUPINFO si ={0}; si.hStdOutput = g_hChildStd_OUT_Wr; si.dwFlags |= STARTF_USESTDHANDLES; W::PROCESS_INFORMATION pi ={0}; si.cb=sizeof(si); //NB There can be problem if using spaces inside the path std::string yara_arguments = yara_path + " " + //path to yara executable yara_rules_path + " " + //path to yara rules yara_input_path; //path to yara input file // Create a file batch which run the IdaPython script and execute it /*FILE *YaraLauncherFile = fopen(YaraLauncherBat.c_str(),"w"); fwrite(YaraLauncher.c_str(),strlen(YaraLauncher.c_str()),1,YaraLauncherFile); fclose(YaraLauncherFile);*/ MYINFO("Launching Yara executable %s command line %s ",yara_path.c_str(),yara_arguments.c_str()); if(!W::CreateProcess(yara_path.c_str(),(char *)yara_arguments.c_str(),NULL,NULL,TRUE,CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi)){ MYERRORE("Can't launch Yara Error %d",W::GetLastError()); return false; } //Timeout 30 sec for the YARA processing W::WaitForSingleObject(pi.hProcess,30000); W::CloseHandle(pi.hProcess); W::CloseHandle(pi.hThread); W::CloseHandle(g_hChildStd_OUT_Wr); *piResults = pi; MYINFO("Yara Finished"); return true; }
/** Dump on disk the memory range written on the remote process address space with return a string containing the path of the dumped memory **/ string ProcessInjectionModule::DumpRemoteWriteInterval(WriteInterval* item,W::DWORD pid){ //Dump remote process memory for each item inside the currentWriteSet W::SIZE_T dwBytesRead = 0; UINT32 size = item->getAddrEnd()-item->getAddrBegin(); unsigned char * buffer = (unsigned char *)malloc(size); W::HANDLE process = W::OpenProcess(PROCESS_VM_READ,false,pid); if(W::ReadProcessMemory(process,(W::LPVOID)item->getAddrBegin(),buffer, size,&dwBytesRead)){ string path = config->getWorkingDir()+ "/" + std::to_string((long double)pid) + "_" + getNameFromPid(pid) + ".bin"; Helper::writeBufferToFile(buffer,size,path); MYINFO("Dumped remote injected memory inside pid %d to %s",pid,path.c_str()); return path; } else{ MYERRORE("Error reading injected process %d memory %s",pid,W::GetLastError()); return ""; } }
UINT32 InitFunctionCall::run(ADDRINT curEip,WriteInterval wi){ string idap_res_file = Config::getInstance()->getCurrentDetectedListPath(); string dumpFile = Config::getInstance()->getCurrentDumpFilePath(); if(!existFile(dumpFile)){ MYERRORE("Dump file hasn't been created"); return -1; } launchIdaScript(Config::IDA_PATH, Config::IDAP_BAD_IMPORTS_CHECKER, Config::BAD_IMPORTS_LIST, idap_res_file, dumpFile); //Read the result of IdaPython script FILE *fd = fopen(idap_res_file.c_str(),"r"); UINT32 file_size = getFileSize(fd); char * init_func_detected = (char *)malloc(file_size); fread(init_func_detected,file_size,1,fd); fclose(fd); MYWARN("Found init functions %s\n",init_func_detected); return 0; }
BOOL InitFunctionCall::launchIdaScript(string idaw,string idaPythonScript,string idaPythonInput,string idaPythonOutput,string dumpFile){ string idaScriptLauncher = Config::getInstance()->getBasePath() + IDAPYTHON_LAUNCHER; //Running external idaPython script W::STARTUPINFO si ={0}; W::PROCESS_INFORMATION pi ={0}; si.cb=sizeof(si); // Create a file batch which run the IdaPython script and execute it //Creating the string used to launch the idaPython script std::stringstream idaScriptStream; idaScriptStream << idaw << " -A -S"; idaScriptStream << "\"" << idaPythonScript << " " << idaPythonInput << " " << idaPythonOutput << "\" "; idaScriptStream << dumpFile << " "; string idaScript = idaScriptStream.str(); FILE *idaLauncherFile = fopen(idaScriptLauncher.c_str(),"w"); fwrite(idaScript.c_str(),strlen(idaScript.c_str()),1,idaLauncherFile); fclose(idaLauncherFile); MYINFO("Launching the IdaPython Script %s Containing %s",idaLauncherFile,idaScript.c_str()); if(!W::CreateProcess(idaScriptLauncher.c_str(),NULL,NULL,NULL,FALSE,CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi)){ MYERRORE("Can't launch idaPythonScript"); return false; } W::WaitForSingleObject(pi.hProcess,INFINITE); W::CloseHandle(pi.hProcess); W::CloseHandle(pi.hThread); MYINFO("idaPythonScript Finished"); return true; }