void MACHFile::entryPointLoad() { // nEntryPointOffset=getAddressOfEntryPoint(); // _loadEntryPoint(); if(isMACH64()) { nEntryPointOffset=RVAToOffset64(getEntryPoint()); } else { nEntryPointOffset=RVAToOffset32(getEntryPoint()); } _loadEntryPoint(); }
int entrypoint() { struct DIS_fixed disasm_data; uint32_t ep = getEntryPoint(); uint32_t remaining_size = getFilesize() - ep; uint32_t current_offset = DisassembleAt(&disasm_data, ep, remaining_size); return 0; }
void* kma_malloc(kma_size_t size) { if (debug) printf("\nREQUEST %i\n", size); if (entryPoint == 0) { entryPoint = getEntryPoint(); } int adjustedSize = size + sizeof(buffer); int bufferSize = getBufferSize(adjustedSize); freeListInfo* freeList = getFreeList(bufferSize); if (freeList == NULL) { return NULL; } getSpaceIfNeeded(freeList, bufferSize); return getNextBuffer(freeList); }
int entrypoint() { // Get the offset of the EP uint32_t ep = getEntryPoint(), cur; // Disassemble one instruction at EP struct DIS_fixed instr; cur = DisassembleAt(&instr, ep, *__clambc_filesize - ep); if(cur == ep) // Failed to disasm return 0; // Check if it's "mov ebx, value" if(instr.x86_opcode != OP_MOV || // Not a MOV instr.arg[0].access_type != ACCESS_REG || // Left arg is not a register instr.arg[0].u.reg != REG_EBX || // Left arg is not EBX instr.arg[1].access_type != ACCESS_IMM // Right arg is not an immediate value ) { return 0; } // Take the argument of mov ebx, ... which is the VA of the cyphertext uint32_t va_of_cyphertext = instr.arg[1].u.other; debug("VA of cyphertext is ");debug(va_of_cyphertext); // Make the VA an RVA - that is subtract the imagebase from it uint32_t rva_of_cyphertext = va_of_cyphertext - __clambc_pedata.opt32.ImageBase; debug("RVA of cyphertext is ");debug(rva_of_cyphertext); // Turn the RVA of the cyphertext into a file (raw) offset uint32_t offset_of_cyphertext = pe_rawaddr(rva_of_cyphertext); // If the offset is bad, bail out if(offset_of_cyphertext == PE_INVALID_RVA) { debug("Can't locate the phisical offset of the cyphertext"); return 0; } debug("Cyphertext starts at ");debug(offset_of_cyphertext); // Move to the cyphertext in the file seek(offset_of_cyphertext, SEEK_SET); // Make room for the cyphertext to be read - 10 bytes that is "HELLO WORM" plus one byte for the terminator uint8_t cyphertext[11]; // Read the cyphertext from file into "cyphertext" if(read(cyphertext, 10)!=10) { debug("Can't read 10 bytes of cyphertext\n"); return 0; } // The "decryption" loop - turns the cyphertext into playintext uint8_t current_position, key = 0x29; for(current_position=0; current_position<10; current_position++) { key++; cyphertext[current_position] ^= key; key = cyphertext[current_position]; } // Compare the (now) plaintext with the reference ("HELLO WORM") if(!memcmp(cyphertext, "HELLO WORM", 10)) { cyphertext[10] = 0; // Add a string terminator debug((char *)cyphertext); // Print it, just for fun foundVirus("ClamAV-Test-File-detected-via-bytecode"); // Set the virus name! } return 0; }
bool PluginPackage::fetchInfo() { PLUGIN_LOG("Fetch Info Loading \"%s\"\n", m_path.utf8().data()); // Open the library void *handle = dlopen(m_path.utf8().data(), RTLD_NOW); if(!handle) { PLUGIN_LOG("Couldn't load plugin library \"%s\": %s\n", m_path.utf8().data(), dlerror()); return false; } PLUGIN_LOG("Fetch Info Loaded %p\n", handle); // This object will call dlclose() and set m_module to NULL // when going out of scope. DynamicLibraryCloser dlCloser(&handle); // Get the three entry points we need for Linux Netscape Plug-ins NP_GetMIMEDescriptionFuncPtr NP_GetMIMEDescription; NPP_GetValueProcPtr NP_GetValue; if(!getEntryPoint(handle, "NP_GetMIMEDescription", (void **) &NP_GetMIMEDescription) || !getEntryPoint(handle, "NP_GetValue", (void **) &NP_GetValue)) { // If any of those failed to resolve, fail the entire load return false; } // Get the plugin name and description using NP_GetValue const char *name; const char *description; if(NP_GetValue(NULL, NPPVpluginNameString, &name) != NPERR_NO_ERROR || NP_GetValue(NULL, NPPVpluginDescriptionString, &description) != NPERR_NO_ERROR) { PLUGIN_LOG("Couldn't get name/description using NP_GetValue\n"); return false; } PLUGIN_LOG("Plugin name: \"%s\"\n", name); PLUGIN_LOG("Plugin description: \"%s\"\n", description); m_name = name; m_description = description; // fileName is just the trailing part of the path int last_slash = m_path.reverseFind('/'); if(last_slash < 0) m_fileName = m_path; else m_fileName = m_path.substring(last_slash + 1); // Grab the MIME description. This is in the format, e.g: // application/x-somescriptformat:ssf:Some Script Format String mimeDescription(NP_GetMIMEDescription()); PLUGIN_LOG("MIME description: \"%s\"\n", mimeDescription.utf8().data()); // Clear out the current mappings. m_mimeToDescriptions.clear(); m_mimeToExtensions.clear(); // Split the description into its component entries, separated by // semicolons. Vector<String> mimeEntries; mimeDescription.split(';', true, mimeEntries); // Iterate through the entries, adding them to the MIME mappings. for(Vector<String>::const_iterator it = mimeEntries.begin(); it != mimeEntries.end(); ++it) { // Each part is split into 3 fields separated by colons // Field 1 is the MIME type (e.g "application/x-shockwave-flash"). // Field 2 is a comma separated list of file extensions. // Field 3 is a human readable short description. const String &mimeEntry = *it; Vector<String> fields; mimeEntry.split(':', true, fields); if(fields.size() != 3) { PLUGIN_LOG("Bad MIME entry \"%s\"\n", mimeEntry.utf8().data()); return false; } const String& mimeType = fields[0]; Vector<String> extensions; fields[1].split(',', true, extensions); const String& description = fields[2]; determineQuirks(mimeType); PLUGIN_LOG("mime_type: \"%s\"\n", mimeType.utf8().data()); PLUGIN_LOG("extensions: \"%s\"\n", fields[1].utf8().data()); PLUGIN_LOG("description: \"%s\"\n", description.utf8().data()); // Map the mime type to the vector of extensions and the description if(!extensions.isEmpty()) m_mimeToExtensions.set(mimeType, extensions); if(!description.isEmpty()) m_mimeToDescriptions.set(mimeType, description); } PLUGIN_LOG("Fetch Info Loaded plugin details ok \"%s\"\n", m_path.utf8().data()); // If this plugin needs to be kept in memory, unload the module now // and load it permanently. if (m_quirks.contains(PluginQuirkDontUnloadPlugin)) { dlCloser.ok(); dlclose(handle); load(); } // dlCloser will unload the plugin if required. return true; }
bool PluginPackage::load() { PLUGIN_LOG("tid:%d isActive:%d isLoaded:%d loadCount:%d\n", gettid(), m_freeLibraryTimer.isActive(), m_isLoaded, m_loadCount); if (m_freeLibraryTimer.isActive()) { ASSERT(m_module); m_freeLibraryTimer.stop(); } else if (m_isLoaded) { if (m_quirks.contains(PluginQuirkDontAllowMultipleInstances)) return false; m_loadCount++; PLUGIN_LOG("Already loaded, count now %d\n", m_loadCount); return true; } ASSERT(m_loadCount == 0); ASSERT(m_module == NULL); PLUGIN_LOG("Loading \"%s\"\n", m_path.utf8().data()); // Open the library void *handle = dlopen(m_path.utf8().data(), RTLD_NOW); if(!handle) { PLUGIN_LOG("Couldn't load plugin library \"%s\": %s\n", m_path.utf8().data(), dlerror()); return false; } m_module = handle; PLUGIN_LOG("Fetch Info Loaded %p\n", m_module); // This object will call dlclose() and set m_module to NULL // when going out of scope. DynamicLibraryCloser dlCloser(&m_module); NP_InitializeFuncPtr NP_Initialize; if(!getEntryPoint(m_module, "NP_Initialize", (void **) &NP_Initialize) || !getEntryPoint(handle, "NP_Shutdown", (void **) &m_NPP_Shutdown)) { PLUGIN_LOG("Couldn't find Initialize function\n"); return false; } // Provide the plugin with our browser function table and grab its // plugin table. Provide the Java environment and the Plugin which // can be used to override the defaults if the plugin wants. initializeBrowserFuncs(); // call this afterwards, which may re-initialize some methods, but ensures // that any additional (or changed) procs are set. There is no real attempt // to have this step be minimal (i.e. only what we add/override), since the // core version (initializeBrowserFuncs) can change in the future. initializeExtraBrowserFuncs(&m_browserFuncs); memset(&m_pluginFuncs, 0, sizeof(m_pluginFuncs)); m_pluginFuncs.size = sizeof(m_pluginFuncs); if(NP_Initialize(&m_browserFuncs, &m_pluginFuncs, JSC::Bindings::getJNIEnv()) != NPERR_NO_ERROR) { PLUGIN_LOG("Couldn't initialize plugin\n"); return false; } // Don't close the library - loaded OK. dlCloser.ok(); // Retain the handle so we can close it in the future. m_module = handle; m_isLoaded = true; ++m_loadCount; PLUGIN_LOG("Initial load ok, count now %d\n", m_loadCount); return true; }
bool ApplicationDescription::hasRemoteEntryPoint() const { return getEntryPoint().scheme() == "http" || getEntryPoint().scheme() == "https"; }
void GlyphPositionAdjustments::applyCursiveAdjustments(LEGlyphStorage &glyphStorage, le_bool rightToLeft, const LEFontInstance *fontInstance) { if (! hasCursiveGlyphs()) { return; } le_int32 start = 0, end = fGlyphCount, dir = 1; le_int32 firstExitPoint = -1, lastExitPoint = -1; LEPoint entryAnchor, exitAnchor, pixels; LEGlyphID lastExitGlyphID = 0; float baselineAdjustment = 0; // This removes a possible warning about // using exitAnchor before it's been initialized. exitAnchor.fX = exitAnchor.fY = 0; if (rightToLeft) { start = fGlyphCount - 1; end = -1; dir = -1; } for (le_int32 i = start; i != end; i += dir) { LEGlyphID glyphID = glyphStorage[i]; if (isCursiveGlyph(i)) { if (lastExitPoint >= 0 && getEntryPoint(i, entryAnchor) != NULL) { float anchorDiffX = exitAnchor.fX - entryAnchor.fX; float anchorDiffY = exitAnchor.fY - entryAnchor.fY; baselineAdjustment += anchorDiffY; adjustYPlacement(i, baselineAdjustment); if (rightToLeft) { LEPoint secondAdvance; fontInstance->getGlyphAdvance(glyphID, pixels); fontInstance->pixelsToUnits(pixels, secondAdvance); adjustXAdvance(i, -(anchorDiffX + secondAdvance.fX)); } else { LEPoint firstAdvance; fontInstance->getGlyphAdvance(lastExitGlyphID, pixels); fontInstance->pixelsToUnits(pixels, firstAdvance); adjustXAdvance(lastExitPoint, anchorDiffX - firstAdvance.fX); } } lastExitPoint = i; if (getExitPoint(i, exitAnchor) != NULL) { if (firstExitPoint < 0) { firstExitPoint = i; } lastExitGlyphID = glyphID; } else { if (baselineIsLogicalEnd(i) && firstExitPoint >= 0 && lastExitPoint >= 0) { le_int32 limit = lastExitPoint /*+ dir*/; LEPoint dummyAnchor; if (getEntryPoint(i, dummyAnchor) != NULL) { limit += dir; } for (le_int32 j = firstExitPoint; j != limit; j += dir) { if (isCursiveGlyph(j)) { adjustYPlacement(j, -baselineAdjustment); } } } firstExitPoint = lastExitPoint = -1; baselineAdjustment = 0; } } } }
unsigned long long MACHFile::getEntryPointOffset() { return RVAToOffset(getEntryPoint()); }
/* * addEntry: Adds an entry to a fcb. * * @start: Integer Pointer location of the starting block * @fcBlockID: Integer the target fcb id * @name: String name of the entry * @type: Integer type of the entry * * return 0: successful execution * return -1: file already exists in directory * return -2: error retrieving the parent file control block * return -3: error looking for a free block * return -4: error finding entry in the file control block * return -5: error creating file control block */ int addEntry(int* start, int fcBlockID, char* name, int type) { /* best case: * block: [1, a, b, c, d, e, f, ... ] * average case: * block: [1, a, b, c, 0, 0, 0, ... ] * worst case: * block: [1, 0, 0, 0, 0, 0, 0, ... ] * * Therefore, 7 chars must be skipped before any useful data is reached. */ if (getStart(malloc(1), fcBlockID, name) != -2) { fprintf(stderr, "File already exists in directory.\n"); return -1; } char* fcb = malloc(BLOCK_SIZE); if (get_block(fcBlockID, fcb)) { fprintf(stderr, "Error retrieving the parent file control block.\n"); return -2; } if (getFreeBlock(start)) { fprintf(stderr, "Error looking for a free block.\n"); return -3; } // Position in the file control block int position; if (getEntryPoint(&position, fcb)) { fprintf(stderr, "Error finding entry in the file control block.\n"); return -4; } /* * order of file attributes: * type name start */ fcb[position++] = type; for (unsigned int i = 0; i < strlen(name); i++) { fcb[i + position] = name[i]; } position += MAX_DIRNAME - 1; char* _start = encode_int(*start); for (int i = 0; i < START; i++) { fcb[i + position] = _start[i]; } position += START; if (fcb[position + 1] == '\0') { fcb[position] = ENTRY_END; } if (put_block(fcBlockID, fcb)) { fprintf(stderr, "Error creating file control block.\n"); return -5; } return 0; }
void UVDGBObject::debugPrint() { printf_plugin_debug("\n\n"); uv_addr_t entryPoint = 0; UV_DEBUG(getEntryPoint(&entryPoint)); printf_plugin_debug("entry point: 0x%08X\n", entryPoint); /* FIXME: this causes a crash uvd_bool_t bIsNintendoLogo = false; UV_DEBUG(isNintendoLogo(&bIsNintendoLogo)); printf_plugin_debug("is nintendo logo: %d\n", bIsNintendoLogo); */ std::string title; UV_DEBUG(getTitle(title)); printf_plugin_debug("title: %s\n", title.c_str()); uint32_t manufacturerCode = 0; UV_DEBUG(getManufacturerCode(&manufacturerCode)); printf_plugin_debug("manufacturer code: 0x%08X\n", manufacturerCode); /* UV_DEBUG(getCGBFlags(uint8_t *out)); UV_DEBUG(getNewLicenseeCode(uint16_t *out)); UV_DEBUG(getSGBFlags(uint8_t *out)); UV_DEBUG(isSGBEnabled(uvd_bool_t *out)); UV_DEBUG(getCartridgeType(uint8_t *out)); */ uint32_t ROMSize = 0; UV_DEBUG(getROMSize(&ROMSize)); printf_plugin_debug("ROM size (bytes): 0x%08X\n", ROMSize); uint8_t ROMSizeRaw = 0; UV_DEBUG(getROMSizeRaw(&ROMSizeRaw)); printf_plugin_debug("ROM size (raw): 0x%02X\n", ROMSizeRaw); uint32_t saveRAMSize = 0; UV_DEBUG(getSaveRAMSize(&saveRAMSize)); printf_plugin_debug("Save RAM size (bytes): 0x%08X\n", saveRAMSize); uint8_t saveRAMSizeRaw = 0; UV_DEBUG(getSaveRAMSizeRaw(&saveRAMSizeRaw)); printf_plugin_debug("save RAM size (raw): 0x%02X\n", saveRAMSizeRaw); /* UV_DEBUG(getDestinationCode(uint8_t *out)); UV_DEBUG(getOldLicenseeCode(uint8_t *out)); UV_DEBUG(getMaskROMVersioNumber(uint8_t *out)); */ uvd_bool_t headerChecksumValid = false; uint8_t headerChecksumFromFile = 0; uint8_t headerChecksumComputed = 0; UV_DEBUG(getHeaderChecksum(&headerChecksumFromFile)); UV_DEBUG(computeHeaderChecksum(&headerChecksumComputed)); UV_DEBUG(isHeaderChecksumValid(&headerChecksumValid)); printf_plugin_debug("header checksum, computed: 0x%02X, from file: 0x%02X, valid: %d\n", headerChecksumComputed, headerChecksumFromFile, headerChecksumValid); uvd_bool_t globalChecksumValid = false; uint16_t globalChecksumFromFile = 0; uint16_t globalChecksumComputed = 0; UV_DEBUG(getGlobalChecksum(&globalChecksumFromFile)); UV_DEBUG(computeGlobalChecksum(&globalChecksumComputed)); UV_DEBUG(isGlobalChecksumValid(&globalChecksumValid)); printf_plugin_debug("global checksum, computed: 0x%04X, from file: 0x%04X, valid: %d\n", globalChecksumComputed, globalChecksumFromFile, globalChecksumValid); printf_plugin_debug("\n\n"); }
void main (int argc, char **argv) { int fd; char *mmapped; int rc; struct stat stbuf; int filesize; char *filename = argv[1]; struct mach_header *mh; int i,j ; int magic; char *sysent = NULL; char *mach = NULL; char *xnuSig = NULL; int showUNIX = 1, showMach = 1; int suppressEnosys = 1; int kexts = 0; if (!filename) { fprintf (stderr,"Usage: joker _filename_\n", argv[0]); fprintf (stderr," _filename_ should be a decrypted iOS kernelcache. Tested on 3.x-4.x-5.x-6.0\n"); fprintf (stderr, "Stable version (no symbolification/sysctl/etc here yet)\n"); exit(0);} rc = stat(filename, &stbuf); if (rc == -1) { perror ("stat"); exit (1); } filesize = stbuf.st_size; fd = open (argv[1], O_RDONLY); if (fd < 0) { perror ("open"); exit(2);} mmapped = mmap(NULL, filesize, // size_t len, PROT_READ, // int prot, MAP_SHARED | MAP_FILE, // int flags, fd, // int fd, 0); // off_t offset); if (!mmapped) { perror ("mmap"); exit(3);} processFile(mmapped); mh = (struct mach_header *) (mmapped); switch (mh->magic) { case 0xFEEDFACE: /* Good, this is a Mach-O */ if (mh->cputype == 12) /* ARM */ { // This is an ARM binary. Good. printf ("This is an ARM binary. Applying iOS kernel signatures\n"); } break; case 0xbebafeca: fprintf (stderr, "This is an Intel FAT binary, but I can't handle these yet\n"); exit(5); default: fprintf(stderr, "I have no idea how to handle a file with a magic of %p\n", magic); exit(6); } printf ("Entry point is 0x%llx..", getEntryPoint()); for (i = 0; i < filesize-50; i++) { if (!xnuSig && memcmp(&mmapped[i], XNUSIG, strlen(XNUSIG)) == 0) { char buf[80]; xnuSig = mmapped + i + strlen(XNUSIG); memset(buf, '\0', 80); strncpy (buf, xnuSig, 40); // The signature we get is from a panic, with the full path to the // xnu sources. Remove the "/" following the XNU version. Because the // memory is mmap(2)ed read only, we have to copy this first. char *temp = strstr(buf, "/"); if (temp) { *temp = '\0'; } xnuSig = buf; printf ("..This appears to be XNU %s\n", xnuSig); } if (memcmp(&mmapped[i], SIG1, 20) == 0) { if (memcmp(&mmapped[i+24], SIG1_SUF, 16) == 0) { printf ("Sysent offset in file/memory (for patching purposes): %p/%p\n",i-8,findAddressOfOffset(i -8)); sysent = mmapped + i - 24 ; // if (xnuSig) break; } } if (showMach) { if (! mach && (memcmp(&mmapped[i], &mmapped[i+40], 40 ) == 0) && (memcmp(&mmapped[i], &mmapped[i+32], 32 ) == 0) && (memcmp(&mmapped[i], &mmapped[i+24], 24 ) == 0) && (memcmp(&mmapped[i], &mmapped[i+16], 16) == 0) && (memcmp(&mmapped[i], &mmapped[i+24], 24) == 0) && (memcmp(&mmapped[i], &mmapped[i+8], 8 ) == 0) && ( (!*((int *) &mmapped[i])) && *((int *) &mmapped[i+4])) ) { printf ("mach_trap_table offset in file/memory (for patching purposes): 0x%x/%p\n", i,findAddressOfOffset(i)); mach = &mmapped[i]; dumpMachTraps (mach); } } // end showMach } // end for i.. if (!xnuSig) { fprintf (stderr, "This doesn't seem to be a kernel!\n"); exit (7);} if (showUNIX) { if (!sysent) { fprintf (stderr, "Unable to find sysent!\n"); exit(8);} if (memcmp(&mmapped[i], "syscall\0exit", 12) == 0) { // syscall_names = &mmapped[i]; printf ("Syscall names are @%x\n", i); } if (suppressEnosys) { int enosys = * ((int *) (sysent + 20 + 24*4)); printf ("Suppressing enosys (%p)\n", enosys); } for (i = 0; i < SYS_MAXSYSCALL ; i++) { int suppress = 0; int thumb = 0; int addr = * ((int *) (sysent + 20 + 24*i)); if (addr == *((int *)(sysent + 20 + 24 * 8))) suppress =1; if ((addr % 4) == 1) { addr--; thumb++; } if ((addr % 4) == -3) { addr--; thumb++; } if (!suppress) printf ("%d. %-20s %x %s\n", i,syscall_names[i], addr, (thumb? "T": "-")); // skip to next post null byte - unfortunately wont work due to optimizations // putting some of the system call name strings elsewhere (in their first appearance // in the binary) // for (; *syscall_names; syscall_names++); // syscall_names++; } } // showUNIX // Do KEXTs // To do the kexts, we load the dictionary of PRELINK_INFO { char *kextPrelinkInfo = (char *) malloc(1000000); CFDictionaryRef dict; char *kextNamePtr; char *kextLoadAddr; char kextName[256]; char loadAddr[16]; char *temp = kextPrelinkInfo; extern char *g_SegName; g_SegName = "__PRELINK_INFO"; void *seg = MachOGetSection("__PRELINK_INFO"); kextPrelinkInfo = (char *) (mmapped + MachOGetSegmentOffset(seg)); temp = kextPrelinkInfo; kextNamePtr = strstr(temp,"CFBundleName</key>"); // This is EXTREMELY quick and dirty, but I can't find a way to load a CFDictionary // directly from XML data, so it will do for now.. while (kextNamePtr) { temp = strstr(kextNamePtr, "</string>"); // overflow, etc.. memset(kextName, '\0', 256); strncpy (kextName, kextNamePtr + 26, temp - kextNamePtr - 26); printf("Kext: %s ", kextName); temp += 15; // _PrelinkExecutableLoadAddr kextNamePtr = strstr(temp, "CFBundleIdentifier"); if (kextNamePtr) { temp = strstr(kextNamePtr,"</string>"); memset(kextName,'\0',256); strncpy(kextName, kextNamePtr + 32, temp - kextNamePtr - 32); printf ("(%s)\n", kextName); } kextNamePtr = strstr(temp,"CFBundleName</key>"); kexts++; } } printf("Got %d kexts. done\n", kexts); }