akvirtualcamera/ports/deploy/tools/binary_pecoff.py
2020-06-05 19:09:17 -03:00

179 lines
5.6 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Webcamoid, webcam capture application.
# Copyright (C) 2017 Gonzalo Exequiel Pedone
#
# Webcamoid is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Webcamoid is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Webcamoid. If not, see <http://www.gnu.org/licenses/>.
#
# Web-Site: http://webcamoid.github.io/
import mimetypes
import os
import struct
import sys
import tools.binary
class DeployToolsBinary(tools.binary.DeployToolsBinary):
def __init__(self):
super().__init__()
def isValid(self, path):
mimetype, _ = mimetypes.guess_type(path)
if mimetype == 'application/x-msdownload':
return True
if mimetype != 'application/octet-stream':
return False
with open(path, 'rb') as f:
if f.read(2) != b'MZ':
return []
f.seek(0x3c, os.SEEK_SET)
peHeaderOffset = struct.unpack('I', f.read(4))
f.seek(peHeaderOffset[0], os.SEEK_SET)
peSignatue = f.read(4)
if peSignatue != b'PE\x00\x00':
return False
return True
# https://msdn.microsoft.com/en-us/library/windows/desktop/ms680547(v=vs.85).aspx
# https://upload.wikimedia.org/wikipedia/commons/1/1b/Portable_Executable_32_bit_Structure_in_SVG_fixed.svg
def dump(self, binary):
dllImports = set()
if not os.path.exists(binary) or not os.path.isfile(binary):
return dllImports
with open(binary, 'rb') as f:
# Check DOS header signature.
if f.read(2) != b'MZ':
return []
# Move to COFF header.
f.seek(0x3c, os.SEEK_SET)
peHeaderOffset = struct.unpack('I', f.read(4))
f.seek(peHeaderOffset[0], os.SEEK_SET)
peSignatue = f.read(4)
# Check COFF header signature.
if peSignatue != b'PE\x00\x00':
return []
# Read COFF header.
coffHeader = struct.unpack('HHIIIHH', f.read(20))
nSections = coffHeader[1]
sectionTablePos = coffHeader[5] + f.tell()
# Read magic signature in standard COFF fields.
peType = 'PE32' if f.read(2) == b'\x0b\x01' else 'PE32+'
# Move to data directories.
f.seek(102 if peType == 'PE32' else 118, os.SEEK_CUR)
# Read the import table.
importTablePos, importTableSize = struct.unpack('II', f.read(8))
# Move to Sections table.
f.seek(sectionTablePos, os.SEEK_SET)
sections = []
idataTablePhysical = -1
# Search for 'idata' section.
for _ in range(nSections):
# Read section.
section = struct.unpack('8pIIIIIIHHI', f.read(40))
sectionName = section[0].replace(b'\x00', b'')
# Save a reference to the sections.
sections += [section]
if sectionName == b'idata' or sectionName == b'rdata':
idataTablePhysical = section[4]
# If import table was defined calculate it's position in
# the file in relation to the address given by 'idata'.
if importTableSize > 0:
idataTablePhysical += importTablePos - section[2]
if idataTablePhysical < 0:
return []
# Move to 'idata' section.
f.seek(idataTablePhysical, os.SEEK_SET)
dllList = set()
# Read 'idata' directory table.
while True:
# Read DLL entries.
try:
dllImport = struct.unpack('IIIII', f.read(20))
except:
break
# Null directory entry.
if dllImport[0] | dllImport[1] | dllImport[2] | dllImport[3] | dllImport[4] == 0:
break
# Locate where is located the DLL name in relation to the
# sections.
for section in sections:
if dllImport[3] >= section[2] \
and dllImport[3] < section[1] + section[2]:
dllList.add(dllImport[3] - section[2] + section[4])
break
for dll in dllList:
# Move to DLL name.
f.seek(dll, os.SEEK_SET)
dllName = b''
# Read string until null character.
while True:
c = f.read(1)
if c == b'\x00':
break
dllName += c
try:
dllImports.add(dllName.decode(sys.getdefaultencoding()))
except:
pass
return dllImports
def dependencies(self, binary):
deps = []
for dep in self.dump(binary):
depPath = self.whereBin(dep)
if len(depPath) > 0 and not self.isExcluded(depPath):
deps.append(depPath)
return deps
def name(self, binary):
dep = os.path.basename(binary)
return dep[: dep.find('.')]