def dbupdate(cls, src, pdestdir):
        '''
        when given a directory of updates (CABs/MSUs/ZIPs)
        and no extraction, only set up update files to be added to dbc.
        Destination is where patched files are.
        '''
        extlogger = logging.getLogger("BAM.Pools.ExWkr")

        logmsg = "[EXMGR][DBUP] starting on " + str(src)
        extlogger.log(logging.DEBUG, logmsg)

        # initialize deliverables
        deliverables = None
        newpath = ''

        # indicates that this cab is one of the new update version that MS started using for v1809 and forward
        # can't handle this type of update yet, so skip it.
        if "PSFX" in src or "psfx" in src:
            return deliverables

        hashes = getfilehashes(src)

        if hashes is None:
            return hashes

        if not (validatecab(str(src)) or ispe(str(src))
                or validatezip(str(src))):
            logmsg = "[EXMGR][DBUP] invalid cab/pe/zip"
            extlogger.log(logging.DEBUG, logmsg)
            return deliverables

        newname = src.split("\\")[-1].lstrip()
        newpath = pdestdir + "\\" + newname

        if ".exe" in newname:
            newpath = newpath.split(".exe")[0]
        elif ".cab" in newname:
            newpath = newpath.split(".cab")[0]
        elif ".zip" in newname:
            newpath = newpath.split(".zip")[0]

        deliverables = ((newpath, []), hashes[0], hashes[1])
        # No need to locate nested CABs/MSUs as long the parent update file
        # is found. Revisit if needed

        logmsg = "[EXMGR][DBUP] Extraction (DB update only) task completed for " + src
        extlogger.log(logging.DEBUG, logmsg)

        # Send the job to the next manager (DB will be updated eventually)
        return deliverables
Exemple #2
0
    def cleantask(cls, jobfile, updateid):
        '''
        task to clean up folder before submitting jobs for symbol search
        if item is removed in cleaning, None is returned, else return item
        '''
        clnlogger = logging.getLogger("BAM.Pools.ClnWkr")
        
        results = None

        logmsg = "[CLNMGR] Starting on " + str(jobfile)
        clnlogger.log(logging.DEBUG, logmsg)

        if ispe(jobfile):
            # check db to see if job already exists:
            hashes = getfilehashes(jobfile)

            if hashes is None:
                return hashes

            if wsuse_db.dbentryexistwithsymbols(globs.DBCONN.cursor(),     \
                                globs.PATCHEDFILESDBNAME, hashes[0], hashes[1]):
                # if PE is already in db with symbols obtained,
                # do not retask job to symbol manager, return None instead
                return results
            else:
                pass
                logmsg = "[CLNMGR] continuing forward with " + str(jobfile)
                clnlogger.log(logging.DEBUG, logmsg)

            # getting to this point means item is not in db, may need to come up
            # with case where db needs to update item though
            infolist = {
                    'OriginalFilename': '', 'FileDescription': '', 'ProductName': '',
                    'Comments': '', 'CompanyName': '', 'FileVersion': '',
                    'ProductVersion': '', 'IsDebug': '', 'IsPatched': '',
                    'IsPreReleased': '', 'IsPrivateBuild': '', 'IsSpecialBuild': '',
                    'Language': '', 'PrivateBuild': '', 'SpecialBuild': ''
                    }

            try:
                unpefile = pefile.PE(jobfile, fast_load=True)
            except pefile.PEFormatError as peerror:
                logmsg = "[WSUS_DB] skipping " + str(jobfile) + " due to exception: " + peerror.value
                clnlogger.log(logging.ERROR, logmsg)
                return results

            infolist['fileext'], infolist['stype'] = pebinarytype(unpefile)
            infolist['arch'] = getpearch(unpefile)
            infolist['age'] = getpeage(unpefile)
            infolist['strippedpe'] = ispedbgstripped(unpefile)
            infolist['builtwithdbginfo'] = ispebuiltwithdebug(unpefile)            

            direntires=[ pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_DEBUG'],    \
                pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_RESOURCE'] ]
            unpefile.parse_data_directories(directories=direntires)
            infolist['pdbfilename'] = getpepdbfilename(unpefile)
            infolist['signature'] = getpesigwoage(unpefile)

            # a PE only have 1 VERSIONINFO, but multiple language strings
            # More information on different properites can be found at
            # https://msdn.microsoft.com/en-us/library/windows/desktop/aa381058
            # https://msdn.microsoft.com/en-us/library/windows/desktop/aa381049
            if getattr(unpefile, "VS_VERSIONINFO", None) is not None and \
                getattr(unpefile, "FileInfo", None) is not None:
                    for fileinfoentries in unpefile.FileInfo:
                        for fileinfoentry in fileinfoentries:
                            if getattr(fileinfoentry, "StringTable", None) is not None:
                                for strtable in fileinfoentry.StringTable:
                                    # Currently only handling unicode en-us
                                    if strtable.LangID[:4] == b'0409' or \
                                            (strtable.LangID[:4] == b'0000' and
                                            (strtable.LangID[4:] == b'04b0' or
                                            strtable.LangID[4:] == b'04B0')):
                                        infolist["Language"] \
                                            = strtable.LangID.decode("utf-8")
                                        for field, value in strtable.entries.items():
                                            dfield = field.decode('utf-8')
                                            dvalue = value.decode('utf-8')
                                            if dfield == "OriginalFilename":
                                                infolist["OriginalFilename"] \
                                                    = dvalue
                                            if dfield == "FileDescription":
                                                infolist["FileDescription"] \
                                                    = dvalue
                                            if dfield == "ProductName":
                                                infolist["ProductName"] \
                                                    = dvalue
                                            if dfield == "Comments":
                                                infolist["Comments"] \
                                                    = dvalue
                                            if dfield == "CompanyName":
                                                infolist["CompanyName"] \
                                                    = dvalue
                                            if dfield == "FileVersion":
                                                infolist["FileVersion"] \
                                                    = dvalue
                                            if dfield == "ProductVersion":
                                                infolist["ProductVersion"] \
                                                    = dvalue
                                            if dfield == "IsDebug":
                                                infolist["IsDebug"] \
                                                    = dvalue
                                            if dfield == "IsPatched":
                                                infolist["IsPatched"] \
                                                    = dvalue
                                            if dfield == "IsPreReleased":
                                                infolist["IsPreReleased"] \
                                                    = dvalue
                                            if dfield == "IsPrivateBuild":
                                                infolist["IsPrivateBuild"] \
                                                    = dvalue
                                            if dfield == "IsSpecialBuild":
                                                infolist["IsSpecialBuild"] \
                                                    = dvalue
                                            if dfield == "PrivateBuild":
                                                infolist["PrivateBuild"] \
                                                    = dvalue
                                            if dfield == "SpecialBuild":
                                                infolist["SpecialBuild"] \
                                                    = dvalue
            # Get the OS this PE is designed towards.
            # Microsoft PE files distributed via Microsoft's Updates typically
            # use the ProductVersion file properties to indicate the OS a specific
            # PE file is built towards.
            # If this is a Microsoft binary, the Product version is typically
            # the OS version it was built towards, but other products this is not
            # necessarily true
            if infolist['ProductName'].find("Operating System") != -1:
                infolist['osver'] = "NT" + infolist['ProductVersion']
            else:
                infolist['osver'] = "UNKNOWN"

            unpefile.close()

            results = ((str(jobfile), updateid), hashes[0], hashes[1], infolist)
        else:
            # if jobfile is not a PE, then check if it's a cab. If not a cab, remove it.
            if not validatecab(str(jobfile)):
                logmsg = "[CLNMGR] cleantask: Removing " + str(jobfile)
                clnlogger.log(logging.DEBUG, logmsg)

                rmfile(jobfile)

                logmsg = "[CLNMGR] " + str(jobfile) + " removed, not PE or cab file"
                clnlogger.log(logging.DEBUG, logmsg)
            else:
                pass
                logmsg = "[CLNMGR] " + str(jobfile) + " is nested cab, skipping"
                clnlogger.log(logging.DEBUG, logmsg)
            return results

        logmsg = "[CLNMGR] completed one cleantask for " + str(jobfile)
        clnlogger.log(logging.DEBUG, logmsg)

        return results
Exemple #3
0
    def extracttask(cls, src, pdir, dst):
        '''
        task for workers to extract contents of .cab file and return
        directory of result to for use by cleaner
        '''
        extlogger = logging.getLogger("BAM.Pools.ExWkr")

        hashes = getfilehashes(src)

        if hashes is None:
            return hashes

        entryexists = False
        if cls.verifyentry(src, hashes[0], hashes[1], extlogger):
            entryexists = True

        logmsg = "[EXMGR] started on " + str(src) + " extracting files to " + str(dst)
        extlogger.log(logging.DEBUG, logmsg)

        # initialize deliverables
        deliverables = None

        # indicates that this cab is one of the new update version that MS started using for v1809 and forward
        # can't handle this type of update yet, so skip it.
        if "PSFX" in src or "psfx" in src:
            return deliverables

        newname = src.split("\\")[-1].lstrip()

        # If the files being worked on is a PE file
        # see if it can be opened with 7z.exe and that
        # it has PE files. Otherwise, skip to other
        # update files.
        if ispe(src):
            logmsg = "[EXMGR] extracting PE file (" + src + ")..."
            extlogger.log(logging.DEBUG, logmsg)

            newdir = (dst + "\\" + newname).split(".exe")[0]
            try:
                os.mkdir(newdir)
            except FileExistsError:
                pass
            except OSError as oserror:
                logmsg = "[EXMGR] OSError creating new directory... skipping extraction for (" + \
                    src + "). Error: " + str(oserror)
                extlogger.log(logging.ERROR, logmsg)
                return deliverables

            if not entryexists and cls.perform7zextract(src, newdir, extlogger) is None:
                return deliverables

            deliverables = ((newdir, []), hashes[0], hashes[1])

            # if nothing was extracted, remove the directory to clean up
            try:
                os.rmdir(newdir)
            except OSError:
                pass
        else:
            if not validatecab(str(src)):
                logmsg = "[EXMGR] {-} invalid file: " + src
                extlogger.log(logging.ERROR, logmsg)
                return None

            # make new directory to hold extracted files
            newdir = ""
            # if this is true, this must be a nested cab file
            if dst in src:
                newdir = str(os.path.dirname(src))
            # otherwise the cab is brand new and should create a newdir in dst
            else:
                if ".cab" in newname:
                    newdir = (dst + "\\" + newname).split(".cab")[0]
                elif ".msu" in newname:
                    newdir = (dst + "\\" + newname).split(".msu")[0]

            try:
                os.mkdir(newdir)
            except FileExistsError:
                pass
            except OSError as oserror:
                logmsg = "[EXMGR] OSError creating new directory... skipping extraction for (" + \
                    src + "). Error: " + str(oserror)
                extlogger.log(logging.ERROR, logmsg)
                return deliverables                

            if not entryexists:
                # extract .dll, .exe and .sys first
                cls.performcabextract("*.dll", src, newdir, extlogger)
                cls.performcabextract("*.exe", src, newdir, extlogger)
                cls.performcabextract("*.sys", src, newdir, extlogger)

            deliverables = ((newdir, []), hashes[0], hashes[1])

            # search through rest of .cab for nested cabs or msus to extract
            # again
            if not entryexists:
                listing = cls.performcablisting(src, extlogger)

                if listing is None:
                    return deliverables

                stroutput = listing.decode("ascii").split("\r\n")

                # indicates that this cab is one of the new update version that MS started using for v1809 and forward
                # can't handle this type of update yet, so skip it.
                if "psfx" in stroutput[3] or "PSFX" in stroutput[4]:
                    return deliverables

                for line in stroutput:
                    if line.endswith(".cab") or line.endswith(".msu"):

                        # expand that line only to start another thread on it
                        potentialfile = line.split(":")[-1].lstrip()

                        # make a new directory to store the nested cab
                        # nested cabs with the same name may exists, keep contents
                        # under the newly created extracted directory for update
                        parentdir = src.split("\\")[-1][0:-4]
                        ncabdir = str(dst) + "\\" + str(parentdir) + "\\" + str(potentialfile)[0:-4]

                        if not os.path.exists(ncabdir):
                            try:
                                os.mkdir(ncabdir)
                                ncabdir = Path(ncabdir).resolve()

                            except OSError as error:
                                logmsg = "[EXMGR] {-} unable to make nested cab directory: " + str(error)
                                extlogger.log(logging.ERROR, logmsg)
                                break

                        logmsg = "[EXMGR] beginning extraction of nestedcab: " + str(src)
                        extlogger.log(logging.DEBUG, logmsg)
                        extractstdout = cls.performcabextract(potentialfile, src, str(ncabdir), extlogger)

                        if extractstdout is not None:
                            # Case where there exists nested cabs with a .manifest file
                            newpath = None
                            for root, dummy, cabs in os.walk(ncabdir):
                                for cab in cabs:
                                    if str(cab) == potentialfile:
                                        newpath = Path(os.path.join(root, cab)).resolve()
                                        break

                            if newpath is None:
                                continue

                            # if file is not a cab/msu, remove it since that's all we're interested
                            # in at this point
                            if not validatecab(str(newpath)):
                                logmsg = "[EXMGR] {-} extracttask: " + str(newpath) + " extracted from " + str(src) +  " is not a validate cab"
                                extlogger.log(logging.ERROR, logmsg)

                                logmsg = "[EXMGR] extracttask: Removing " + str(newpath)
                                extlogger.log(logging.ERROR, logmsg)

                                rmfile(newpath)

                                continue

                            logmsg = "[EXMGR] Creating " + str(newpath) + " for new thread..."
                            extlogger.log(logging.DEBUG, logmsg)

                            # return new location of extracted cab for addition to job queue
                            deliverables[0][1].append(str(newpath))

        logmsg = "[EXMGR] Extraction task completed for " + src
        extlogger.log(logging.DEBUG, logmsg)
        return deliverables