def run(self): """Run analysis. @return: results dict. """ self.key = "static" static = {} if self.task["category"] == "file": if not os.path.exists(self.file_path): return f = File(self.file_path) filename = os.path.basename(self.task["target"]) elif self.task["category"] == "archive": if not os.path.exists(self.file_path): return f = Archive(self.file_path).get_file( self.task["options"]["filename"] ) filename = os.path.basename(self.task["options"]["filename"]) else: return if filename: ext = filename.split(os.path.extsep)[-1].lower() else: ext = None package = self.task.get("package") if package == "generic" and (ext == "elf" or "ELF" in f.get_type()): static["elf"] = ELF(f.file_path).run() static["keys"] = f.get_keys() if package == "exe" or ext == "exe" or "PE32" in f.get_type(): static.update(PortableExecutable(f.file_path).run()) static["keys"] = f.get_keys() if package == "wsf" or ext == "wsf": static["wsf"] = WindowsScriptFile(f.file_path).run() if package in ("doc", "ppt", "xls") or ext in self.office_ext: static["office"] = OfficeDocument(f.file_path, self.task["id"]).run() if package == "pdf" or ext == "pdf": if f.get_content_type() == "application/pdf": static["pdf"] = dispatch( _pdf_worker, (f.file_path,), timeout=self.options.pdf_timeout ) or [] else: static["pdf"] = [] if package == "generic" or ext == "lnk": static["lnk"] = LnkShortcut(f.file_path).run() return static
def run(self): """Run Google play unofficial python api the get the google play information @return: list of google play features """ self.key = "googleplay" googleplay = {} if not HAVE_GOOGLEPLAY: log.error("Unable to import the GooglePlay library, has it been " "installed properly?") return if "file" not in self.task["category"]: return f = File(self.task["target"]) if f.get_name().endswith((".zip", ".apk")) or "zip" in f.get_type(): if not os.path.exists(self.file_path): raise CuckooProcessingError("Sample file doesn't exist: \"%s\"" % self.file_path) android_id = self.options.get("android_id") google_login = self.options.get("google_login") google_password = self.options.get("google_password") # auth_token = self.options.get("auth_token", None) if not android_id and not google_login and not google_password: raise CuckooProcessingError("Google Play Credentials not configured, skip") try: a = APK(self.file_path) if a.is_valid_APK(): package = a.get_package() # Connect api = GooglePlayAPI(android_id) api.login(google_login, google_password, None) # Get the version code and the offer type from the app details app_data = api.details(package) app_detail = app_data.docV2.details.appDetails if not app_detail.installationSize: return googleplay googleplay["title"] = app_detail.title googleplay["app_category"] = app_detail.appCategory._values googleplay["version_code"] = app_detail.versionCode googleplay["app_type"] = app_detail.appType googleplay["content_rating"] = app_detail.contentRating googleplay["developer_email"] = app_detail.developerEmail googleplay["developer_name"] = app_detail.developerName googleplay["developer_website"] = app_detail.developerWebsite googleplay["installation_size"] = app_detail.installationSize googleplay["num_downloads"] = app_detail.numDownloads googleplay["upload_date"] = app_detail.uploadDate googleplay["permissions"] = app_detail.permission._values except (IOError, OSError, zipfile.BadZipfile) as e: raise CuckooProcessingError("Error opening file %s" % e) return googleplay
def run(self): """Run androguard to extract static android information @return: list of static features """ self.key = "apkinfo" apkinfo = {} if "file" not in self.task["category"]: return from androguard.core.bytecodes.apk import APK from androguard.core.bytecodes.dvm import DalvikVMFormat from androguard.core.analysis.analysis import uVMAnalysis from androguard.core.analysis import analysis f = File(self.task["target"]) if f.get_name().endswith((".zip", ".apk")) or "zip" in f.get_type(): if not os.path.exists(self.file_path): raise CuckooProcessingError("Sample file doesn't exist: \"%s\"" % self.file_path) try: a = APK(self.file_path) if a.is_valid_APK(): manifest = {} apkinfo["files"] = self._apk_files(a) manifest["package"] = a.get_package() # manifest["permissions"]=a.get_details_permissions_new() manifest["main_activity"] = a.get_main_activity() manifest["activities"] = a.get_activities() manifest["services"] = a.get_services() manifest["receivers"] = a.get_receivers() # manifest["receivers_actions"]=a.get__extended_receivers() manifest["providers"] = a.get_providers() manifest["libraries"] = a.get_libraries() apkinfo["manifest"] = manifest # apkinfo["certificate"] = a.get_certificate() static_calls = {} if self.check_size(apkinfo["files"]): vm = DalvikVMFormat(a.get_dex()) vmx = uVMAnalysis(vm) static_calls["all_methods"] = self.get_methods(vmx) static_calls["is_native_code"] = analysis.is_native_code(vmx) static_calls["is_dynamic_code"] = analysis.is_dyn_code(vmx) static_calls["is_reflection_code"] = analysis.is_reflection_code(vmx) # static_calls["dynamic_method_calls"]= analysis.get_show_DynCode(vmx) # static_calls["reflection_method_calls"]= analysis.get_show_ReflectionCode(vmx) # static_calls["permissions_method_calls"]= analysis.get_show_Permissions(vmx) # static_calls["crypto_method_calls"]= analysis.get_show_CryptoCode(vmx) # static_calls["native_method_calls"]= analysis.get_show_NativeMethods(vmx) else: log.warning("Dex size bigger than: %s", self.options.decompilation_threshold) apkinfo["static_method_calls"] = static_calls except (IOError, OSError, zipfile.BadZipfile) as e: raise CuckooProcessingError("Error opening file %s" % e) return apkinfo
class TestFile(object): def setup(self): # File() will invoke cwd(), so any CWD is required. set_cwd(tempfile.mkdtemp()) self.path = tempfile.mkstemp()[1] self.file = File(self.path) def test_get_name(self): assert self.path.split(os.sep)[-1] == self.file.get_name() def test_get_data(self): assert "" == self.file.get_data() def test_get_size(self): assert 0 == self.file.get_size() def test_get_crc32(self): assert "00000000" == self.file.get_crc32() def test_get_md5(self): assert "d41d8cd98f00b204e9800998ecf8427e" == self.file.get_md5() def test_get_sha1(self): assert "da39a3ee5e6b4b0d3255bfef95601890afd80709" == self.file.get_sha1() def test_get_sha256(self): assert "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" == self.file.get_sha256() def test_get_sha512(self): assert "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e" == self.file.get_sha512() def test_get_ssdeep(self): try: import pydeep assert self.file.get_ssdeep() is not None pydeep # Fake usage. except ImportError: assert self.file.get_ssdeep() is None def test_get_type(self): assert "empty" in self.file.get_type() def test_get_content_type(self): assert self.file.get_content_type() in ["inode/x-empty", "application/x-empty"] def test_get_all_type(self): assert isinstance(self.file.get_all(), dict) def test_get_all_keys(self): for key in ["name", "size", "crc32", "md5", "sha1", "sha256", "sha512", "ssdeep", "type"]: assert key in self.file.get_all()
def test_add_target_file(self): fd, sample_path = tempfile.mkstemp() os.write(fd, os.urandom(64)) os.close(fd) target = File(sample_path) id = add_target(sample_path, "file") db_target = self.d.find_target(id=id) assert id is not None assert db_target.file_size == 64 assert db_target.file_type == target.get_type() assert db_target.md5 == target.get_md5() assert db_target.crc32 == target.get_crc32() assert db_target.sha1 == target.get_sha1() assert db_target.sha256 == target.get_sha256() assert db_target.sha512 == target.get_sha512() assert db_target.ssdeep == target.get_ssdeep() assert db_target.category == "file"
def test_target_to_dict(self): fd, sample_path = tempfile.mkstemp() os.write(fd, os.urandom(64)) os.close(fd) target = File(sample_path) id = add_target(sample_path, category="file") db_target = self.d.find_target(id=id) db_target = db_target.to_dict() assert db_target["id"] == id assert db_target["file_size"] == 64 assert db_target["file_type"] == target.get_type() assert db_target["md5"] == target.get_md5() assert db_target["crc32"] == target.get_crc32() assert db_target["sha1"] == target.get_sha1() assert db_target["sha256"] == target.get_sha256() assert db_target["sha512"] == target.get_sha512() assert db_target["ssdeep"] == target.get_ssdeep() assert db_target["category"] == "file" assert db_target["target"] == sample_path
def test_magic1(self): f = File("tests/files/foo.txt") assert "ASCII text" in f.get_type() assert f.get_content_type() == "text/plain"
def run(self): """Run analysis. @return: results dict. """ self.key = "static" static = {} if self.task["category"] == "file": if not os.path.exists(self.file_path): return f = File(self.file_path) filename = os.path.basename(self.task["target"]) elif self.task["category"] == "archive": if not os.path.exists(self.file_path): return f = Archive(self.file_path).get_file( self.task["options"]["filename"]) filename = os.path.basename(self.task["options"]["filename"]) else: return if filename: ext = filename.split(os.path.extsep)[-1].lower() else: ext = None package = self.task.get("package") if package == "generic" and (ext == "elf" or "ELF" in f.get_type()): static["elf"] = ELF(f.file_path).run() static["keys"] = f.get_keys() if package == "exe" or ext == "exe" or "PE32" in f.get_type(): static.update(PortableExecutable(f.file_path).run()) static["keys"] = f.get_keys() if package == "wsf" or ext == "wsf": static["wsf"] = WindowsScriptFile(f.file_path).run() if package in ("doc", "ppt", "xls") or ext in self.office_ext: static["office"] = OfficeDocument(f.file_path, self.task["id"]).run() if package == "pdf" or ext == "pdf": if f.get_content_type() == "application/pdf": static["pdf"] = dispatch( _pdf_worker, (f.file_path, ), timeout=self.options.pdf_timeout) or [] else: static["pdf"] = [] if package == "generic" or ext == "lnk": static["lnk"] = LnkShortcut(f.file_path).run() if package == "apk" or ext == "apk" or any(t in f.get_type() for t in ("JAR", "Zip")): static["apkinfo"] = AndroidPackage(f.file_path).run() return static
class TestFile(object): def setup(self): # File() will invoke cwd(), so any CWD is required. set_cwd(tempfile.mkdtemp()) self.fd, self.path = tempfile.mkstemp() self.file = File(self.path) def test_get_name(self): assert self.path.split(os.sep)[-1] == self.file.get_name() def test_get_data(self): assert "" == self.file.get_data() def test_get_size(self): assert 0 == self.file.get_size() def test_get_crc32(self): assert "00000000" == self.file.get_crc32() def test_get_md5(self): assert "d41d8cd98f00b204e9800998ecf8427e" == self.file.get_md5() def test_get_sha1(self): assert "da39a3ee5e6b4b0d3255bfef95601890afd80709" == self.file.get_sha1( ) def test_get_sha256(self): assert "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" == self.file.get_sha256( ) def test_get_sha512(self): assert "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e" == self.file.get_sha512( ) def test_get_ssdeep(self): try: import pydeep assert self.file.get_ssdeep() is not None pydeep # Fake usage. except ImportError: assert self.file.get_ssdeep() is None def test_get_type(self): assert "empty" in self.file.get_type() def test_get_content_type(self): assert self.file.get_content_type() in [ "inode/x-empty", "application/x-empty" ] def test_get_all_type(self): assert isinstance(self.file.get_all(), dict) def test_get_all_keys(self): for key in [ "name", "size", "crc32", "md5", "sha1", "sha256", "sha512", "ssdeep", "type" ]: assert key in self.file.get_all() def test_read(self): os.write(self.fd, os.urandom(64)) os.close(self.fd) read1 = open(self.file.file_path, "rb").read() read2 = self.file.read() assert read1 == read2 def test_get_filepointer_read(self): os.write(self.fd, "doge42") os.close(self.fd) assert self.file.get_filepointer().read() == "doge42" def test_get_filepointer_write(self): fp = self.file.get_filepointer(mode="wb") fp.write("doge") fp.close() assert open(self.file.file_path, "rb").read() == "doge"
def run(self): """Run androguard to extract static android information @return: list of static features """ self.key = "apkinfo" apkinfo = {} if "file" not in self.task["category"]: return from androguard.core.bytecodes.apk import APK from androguard.core.bytecodes.dvm import DalvikVMFormat from androguard.core.analysis.analysis import uVMAnalysis from androguard.core.analysis import analysis f = File(self.task["target"]) if f.get_name().endswith((".zip", ".apk")) or "zip" in f.get_type(): if not os.path.exists(self.file_path): raise CuckooProcessingError( "Sample file doesn't exist: \"%s\"" % self.file_path) try: a = APK(self.file_path) if a.is_valid_APK(): manifest = {} apkinfo["files"] = self._apk_files(a) manifest["package"] = a.get_package() # manifest["permissions"]=a.get_details_permissions_new() manifest["main_activity"] = a.get_main_activity() manifest["activities"] = a.get_activities() manifest["services"] = a.get_services() manifest["receivers"] = a.get_receivers() # manifest["receivers_actions"]=a.get__extended_receivers() manifest["providers"] = a.get_providers() manifest["libraries"] = a.get_libraries() apkinfo["manifest"] = manifest # apkinfo["certificate"] = a.get_certificate() static_calls = {} if self.check_size(apkinfo["files"]): vm = DalvikVMFormat(a.get_dex()) vmx = uVMAnalysis(vm) static_calls["all_methods"] = self.get_methods(vmx) static_calls[ "is_native_code"] = analysis.is_native_code(vmx) static_calls["is_dynamic_code"] = analysis.is_dyn_code( vmx) static_calls[ "is_reflection_code"] = analysis.is_reflection_code( vmx) # static_calls["dynamic_method_calls"]= analysis.get_show_DynCode(vmx) # static_calls["reflection_method_calls"]= analysis.get_show_ReflectionCode(vmx) # static_calls["permissions_method_calls"]= analysis.get_show_Permissions(vmx) # static_calls["crypto_method_calls"]= analysis.get_show_CryptoCode(vmx) # static_calls["native_method_calls"]= analysis.get_show_NativeMethods(vmx) else: log.warning("Dex size bigger than: %s", self.options.decompilation_threshold) apkinfo["static_method_calls"] = static_calls except (IOError, OSError, zipfile.BadZipfile) as e: raise CuckooProcessingError("Error opening file %s" % e) return apkinfo
def run(self): """Run Google play unofficial python api the get the google play information @return: list of google play features """ self.key = "googleplay" googleplay = {} if not HAVE_GOOGLEPLAY: log.error("Unable to import the GooglePlay library, has it been " "installed properly?") return if "file" not in self.task["category"]: return from androguard.core.bytecodes.apk import APK f = File(self.task["target"]) if f.get_name().endswith((".zip", ".apk")) or "zip" in f.get_type(): if not os.path.exists(self.file_path): raise CuckooProcessingError( "Sample file doesn't exist: \"%s\"" % self.file_path) android_id = self.options.get("android_id") google_login = self.options.get("google_login") google_password = self.options.get("google_password") # auth_token = self.options.get("auth_token", None) if not android_id and not google_login and not google_password: raise CuckooProcessingError( "Google Play Credentials not configured, skip") try: a = APK(self.file_path) if a.is_valid_APK(): package = a.get_package() # Connect api = GooglePlayAPI(android_id) api.login(google_login, google_password, None) # Get the version code and the offer type from the app details app_data = api.details(package) app_detail = app_data.docV2.details.appDetails if not app_detail.installationSize: return googleplay googleplay["title"] = app_detail.title googleplay["app_category"] = app_detail.appCategory._values googleplay["version_code"] = app_detail.versionCode googleplay["app_type"] = app_detail.appType googleplay["content_rating"] = app_detail.contentRating googleplay["developer_email"] = app_detail.developerEmail googleplay["developer_name"] = app_detail.developerName googleplay[ "developer_website"] = app_detail.developerWebsite googleplay[ "installation_size"] = app_detail.installationSize googleplay["num_downloads"] = app_detail.numDownloads googleplay["upload_date"] = app_detail.uploadDate googleplay["permissions"] = app_detail.permission._values except (IOError, OSError, zipfile.BadZipfile) as e: raise CuckooProcessingError("Error opening file %s" % e) return googleplay
def run(self): """Run Floss on analyzed file. @return: Floss results dict. """ self.key = "strings" self.floss = self.options.get("floss") self.MIN_STRINGLEN = int(self.options.get("min_str_len")) self.MAX_STRINGLEN = self.options.get("max_str_len") self.MAX_STRINGCNT = self.options.get("max_str_cnt") self.MAX_FILESIZE = 16*1024*1024 STRING_TYPES = [ "decoded", "stack", "static" ] strings = {} if self.task["category"] == "file": if not os.path.exists(self.file_path): raise CuckooProcessingError( "Sample file doesn't exist: \"%s\"" % self.file_path ) try: f = File(self.file_path) filename = os.path.basename(self.task["target"]) base_name = os.path.splitext(filename)[0] ext = filename.split(os.path.extsep)[-1].lower() data = open(self.file_path, "r").read(self.MAX_FILESIZE) except (IOError, OSError) as e: raise CuckooProcessingError("Error opening file %s" % e) # Extract static strings static_strings = re.findall("[\x1f-\x7e]{" + str(self.MIN_STRINGLEN) + ",}", data) for s in re.findall("(?:[\x1f-\x7e][\x00]){" + str(self.MIN_STRINGLEN) + ",}", data): static_strings.append(s.decode("utf-16le")) if self.MAX_STRINGLEN != 0: for i, s in enumerate(static_strings): static_strings[i] = s[:self.MAX_STRINGLEN] if self.MAX_STRINGCNT != 0 and len(static_strings) > self.MAX_STRINGCNT: static_strings = static_strings[:self.MAX_STRINGCNT] static_strings.append("[snip]") package = self.task.get("package") if self.floss and (package == "exe" or ext == "exe" or "PE32" in f.get_type()): # Disable floss verbose logging main.set_logging_levels() try: # Prepare Floss for extracting hidden & encoded strings vw = vivisect.VivWorkspace() vw.loadFromFile(self.file_path) vw.analyze() selected_functions = main.select_functions(vw, None) decoding_functions_candidates = id_man.identify_decoding_functions( vw, main.get_all_plugins(), selected_functions ) except Exception as e: raise CuckooProcessingError("Error analyzing file with vivisect: %s" % e) try: # Decode & extract hidden & encoded strings decoded_strings = main.decode_strings( vw, decoding_functions_candidates, self.MIN_STRINGLEN ) decoded_strs = main.filter_unique_decoded(decoded_strings) stack_strings = stackstrings.extract_stackstrings( vw, selected_functions, self.MIN_STRINGLEN ) stack_strings = list(stack_strings) decoded_strings = [x for x in decoded_strs if not x in static_strings] except Exception as e: raise CuckooProcessingError("Error extracting strings with floss: %s" % e) if len(decoded_strings) or len(stack_strings): # Create annotated scripts if self.options.get("idapro_str_sct"): idapro_sct_name = base_name + ".idb" strings["idapro_sct_name"] = idapro_sct_name main.create_ida_script( self.file_path, os.path.join(self.str_script_path, idapro_sct_name), decoded_strings, stack_strings ) if self.options.get("radare_str_sct"): radare_sct_name = base_name + ".r2" strings["radare_sct_name"] = radare_sct_name main.create_r2_script( self.file_path, os.path.join(self.str_script_path, radare_sct_name), decoded_strings, stack_strings ) if self.options.get("x64dbg_str_sct"): x64dbg_sct_name = base_name + ".json" strings["x64dbg_sct_name"] = x64dbg_sct_name imagebase = vw.filemeta.values()[0]['imagebase'] main.create_x64dbg_database( self.file_path, os.path.join(self.str_script_path, base_name + ".json"), imagebase, decoded_strings ) # convert Floss strings into regular, readable strings for idx, s in enumerate(decoded_strings): decoded_strings[idx] = main.sanitize_string_for_printing(s.s) for idx, s in enumerate(stack_strings): stack_strings[idx] = s.s results = [decoded_strings, stack_strings, static_strings] for idx, str_type in enumerate(STRING_TYPES): strings[str_type] = results[idx] else: strings["static"] = static_strings return strings