[Macro] VBA + Form Object + Obfuscation
0x00. Intro¶
CFBF 파일 포맷 분석부터 이를 이용한 다양한 형태의 악성코드를 분석해 보았다.
- 관련 글 보러가기
그런데 최근 트렌드 마이크로의 블로그를 통해 새로운 형태의 Macro 악성코드 분석 정보가 공개되었다. 해당 악성코드는 Macro의 Form Object를 이용해 난독화를 적용한 형태의 악성코드이며 이를 통해 최근 유행하고 있는 랜섬웨어를 배포하는 형태를 띄고 있다.
- 감염 방식 : 이메일을 통한 Spear-Phishing, 첨부 파일
- 첨부 파일 형식 : 문서 파일 (doc, xls등)
- 동작 방식 : 매크로 기능을 통한 악성코드 실행
- 실행된 악성코드 목적 : 랜섬웨어
따라서 해당 문서 파일 포맷 분석을 통해 해당 악성동작을 탐지해 보자.
- 개발 언어 : Python 2.7.x
- 개발 환경 : ipython Notebook
- 사용 도구 : OffVis, SSView
- 개발 목표
- CFBF 파일 포맷 내의 Macro를 탐지한다.
- 분석 대상 : [SHA-256] 937B31B1838D6AE025BF97CA01329533155AD3CA3F0087CA5CF5BAF283CC265C
- 진단 결과 : malwares.com
0x10. 전체 동작¶
0x20. Ukraine 변종(?)¶
이번에 발견된 악성 매크로 파일의 경우 우크라이나 정전사태를 일으킨 악성 문서파일과 상당 부분 유사한 형태를 띄고 있다.
유포 기법 : Spear Phishing
공통점
- 탐지된 문서 파일 형식 : 엑셀, 워드
- 사용된 언어 : 러시아어 ( Codec : 1251 )
- 엑셀 시트명 : ЭтаКнига, Лист1, Лист2, Лист3
- 악성코드 실행 기법 : 매크로, DBD
차이점
- 배포된 악성코드
- 우크라이나 정전사태 관련 악성코드 : BlackEnergy -> MBR 파괴형 악성코드
- 변종 : Locky 랜섬웨어
- 배포된 악성코드
하지만 공통점으로 언급한 사항은 "APT + 매크로" 형태에서 일반적으로 사용되는 방법이라는 점에서 Ukraine의 변종으로 보기보단 이러한 형태로 배포되던 악성코드 중 일부가 ukraine 정전사태에 영향을 미친 것으로 보는게 더 합리적일거라 판단된다.
그리고 파일의 내부 구조는 CFBF 파일 포맷을 따르기 때문에 우크라이나 정전관련 악성 문서 파일 분석시 작성한 코드를 활용하면 내부 코드 추출이 가능하다. ( 동일 코드를 이용한 코드 추출 부분은 "0x99. 참고"를 확인하기 바란다. )
0x30. 분석¶
엑셀은 기본적으로 Visual Basic을 이용한 개발이 가능하도록 개발자 도구를 지원하고 있다. 해당 악성코드 또한 이러한 개발자 도구를 통해 개발되었으므로 엑셀의 개발자 도구를 활용해 내부 코드를 확인할 수 있다.
( 테스트 환경 : 엑셀 2007 )
기본적으로 엑셀 개발자 도구는 "탭"에서 확인할 수 없다. 따라서 우선 개발자 도구 탭부터 보이도록 설정해야 한다.
과정
1) "빠른 실행 도구 모음 사용자 지정" 을 선택한다.
2) "기타 명령" 메뉴를 선택한다.
3) "기본 설정" 메뉴를 선택한다.
4) "리본 메뉴에 개발 도구 탭 표시" 옆의 체크 박스를 클릭해 활성화 한다.
5) "확인" 버튼을 누른다.
설정이 완료되면 "개발자 도구" 탭에서 "Visual Basic"을 선택하면 된다.
Visual Basic에서 "프로젝트"에서 엑셀 파일내에 생성된 시트나 모듈을 선택하면 내부 코드를 볼 수 있다. 이 중 "Module1"을 선택하면 분석 대상 소스를 확인할 수 있다.
엑셀 게임처럼 보이는 코드이지만 CheckBin() 함수를 확인해 보면 10진수로 보이는 문자열을 확인할 수 있고 해당 변수 (somehernya_7)을 코드내에서 검색하면 다음과 같은 처리 구문을 확인할 수 있다.
해당 구문과 같은 방식을 파이썬으로 처리하면 다음과 같다.
somehernya_7 = "1104|1116|1116|1112|1058|1047|1047|1115|1101|1107|1105|1101|1100|1103|1101|1046|1099|1111|1046|1117|1107|1047|1115|1121|1115|1116|1101|1109|1047|1108|1111|1103|1115|1047|1055|1054|1052|1055|1103|1100|1055|1098|1052|1051|1102|1052|1051|1046|1101|1120|1101"
somehernya_7 = somehernya_7.split("|")
out = ""
for c in somehernya_7:
out += chr(int(c) - 1000)
print out.replace("http://", "hxxp://")
해당 경로는 엑셀 파일을 실행했을 때 접속하는 URL로 악성코드 다운로드를 시도하지만 현재 다운로드는 지원하지 않는다.
- 외부 서버 : sekiedge.co.uk ( 119.81.19.188 )
( malwares.com 검색 결과 )
하지만 malwares.com에서 해당 도메인을 확인해 보면 해당 사이트에서 배포된 악성코드에 대한 정보를 확인할 수 있다.
다운로드 파일 정보
- [SHA256] 240B43DFC2712D7D40312E760BCCA5F9C7C259BBFA115C866127027346CB2FA3
- 진단 결과 : malwares.com
생성 파일 정보
- [SHA256] E720F917CD8A02B0372B85068844E132C42EA2C97061B81D378B5A73F9344003
- 진단 결과 : malwares.com
즉, VBA Macro를 이용해 외부 서버에서 다운받아 실행되는 악성코드는 Locky 랜섬웨어이다.
또한 검색을 통해 유사 변종 악성코드를 다운받는 경우를 확인할 수 있으며 그 결과는 다음과 같다.
- 악성코드 배포 도메인
- 2016.03.13 : hxxp://sweetchicory.com/system/logs/45g456jhyfg(malwares.com)
- 2016.03.13 : hxxp://shop.havtoto.bget.ru/system/logs/45g456jhyfg(malwares.com)
- 2016.03.13 : hxxp://idealnaya-para.ru/photo/svadebnye_platya/45g456jhyfg/(malwares.com)
- 2016.02.29 : hxxp://maksi-stroy.com/assets/39e28906/45g456jhyfg(malwares.com)
- 2016.02.24 : hxxp://120.52.72.39/sekiedge.co.uk/c3pr90ntcsf0/system/logs/7647gd7b43f43.exe(malwares.com)
- 2016.02.18 : hxxp://sugarhouse928.com.my/system/logs/7647gd7b43f43.exe(malwares.com)
- 2016.02.18 : hxxp://shop.zoomyoo.com/image/templates/7647gd7b43f43.exe(malwares.com)
- 2016.02.18 : hxxp://acilkiyafetgulertekstil.com/system/logs/7647gd7b43f43.exe(malwares.com)
- 2016.02.18 : hxxp://organichorsesupplements.co.uk/system/logs/7647gd7b43f43.exe(malwares.com)
- 2016.02.18 : hxxp://vipkalyan.com.ua/system/logs/7647gd7b43f43.exe(malwares.com)
- 2016.02.18 : hxxp://merichome.com/system/logs/7647gd7b43f43.exe(malwares.com)
- 2016.02.18 : hxxp://tutikutyu.hu/system/logs/7647gd7b43f43.exe(malwares.com)
- 2016.02.18 : hxxp://kaminus.com.ua/admin/view/7647gd7b43f43.exe(malwares.com)
- 2016.02.18 : hxxp://remont-krovlia.ru/system/cache/7647gd7b43f43.exe(malwares.com)
- 2016.02.18 : hxxp://mppl.ca/system/logs/7647gd7b43f43.exe(malwares.com)
- 2016.02.18 : hxxp://jurisdocs.3forcom.net/system/logs/7647gd7b43f43.exe(malwares.com)
- 2016.02.18 : hxxp://cms.insviluppo.net/images/slides/7647gd7b43f43.exe(malwares.com)
- 2016.02.18 : hxxp://tramviet.vn/system/logs/7647gd7b43f43.exe(malwares.com)
- 배포된 악성코드
- 2016.03.02 : 240B43DFC2712D7D40312E760BCCA5F9C7C259BBFA115C866127027346CB2FA3 -> Ransomware : Locky
- 2016.02.26 : D4FF4B73D7E89F80D78239A349C0197022C9D9306E5B59FDB71894040BC36489 -> Ransomware : Locky
- 2016.02.25 : 1A45085E959A449637A89174B1737F4D03D7E73DD7ACFA3CFB96042A735CF400 -> Ransomware : Locky
- 2016.02.18 : 30587EC7BECBFF5E55F6EFFDD22075568D80EB4A06CE3104502D4D76004E16F3 -> Ransomware : Locky
- 2016.02.18 : 56FC23C1EB3C4EA5F9F7911D8BFA0AF6DF762EB6E22D002DDAD562568606ACC0 -> Ransomware : Locky
- 2015.05.09 : FDD7AB8664EF312E97570CD12B18988E1453432B23A2712E412B8E981BDD52BF -> Trojan : PWS
- 악성코드 C2서버
- 94.242.57.45(malwares.com) : 러시아
- 46.4.239.76(malwares.com) : 독일
- 195.22.28.196(malwares.com) : 포르투갈
- 195.22.28.197(malwares.com) : 포르투갈
- 195.22.28.198(malwares.com) : 포르투갈
- 195.22.28.199(malwares.com) : 포르투갈
배포 이력을 갖는 도메인의 경우 현재 Locky 랜섬웨어를 배포하고 있지만 과거 Sality등을 배포하던 봇넷을 그대로 사용하고 있음을 malwares.com 로그를 통해 확인할 수 있다. 즉, 과거 Sality와 같은 봇넷을 통해 수익을 내던 해커/악성코드 제작자들이 랜섬웨어로 수익모델을 변경했음을 의미하고 있다. 따라서 기존 봇넷 트래킹처럼 랜섬웨어 트래킹이 필요하다.
0x99. 참고¶
from struct import unpack, calcsize
from collections import namedtuple
def read8(data, offset):
return unpack("<B", data[offset])[0]
def read8Ex(data, offset):
return read8(data, offset), offset + 1
def read16(data, offset):
return unpack("<H", data[offset:offset + 2])[0]
def read16Ex(data, offset):
return read16(data, offset), offset + 2
def read32(data, offset):
return unpack("<L", data[offset:offset + 4])[0]
def read32Ex(data, offset):
return read32(data, offset), offset + 4
def writefile(name, data):
file(name, "wb").write(data)
def newMap(name, member):
if isinstance(member, list):
return namedtuple(name, " ".join(member))
else:
return None
def Map(struct_name, buffer, member_name, member_pattern):
return namedtuple(struct_name, member_name)._make(unpack(member_pattern, buffer))
def MapSize(member_pattern):
return calcsize(member_pattern)
def mergeNamedtuple(new_name, namedtuple1, namedtuple2):
return namedtuple(new_name, namedtuple1._fields + namedtuple2._fields)(*(namedtuple1 + namedtuple2))
def addNamedtuple(new_name, namedtuple1, add_member_name, add_member_value):
return namedtuple(new_name, namedtuple1._fields+(add_member_name, ))(*(namedtuple1 + (add_member_value,)))
import os
from oletools import olevba
dir_paths = [r"C:\Users\amanaksu\Dropbox\Sample_Windows\###. CFBF-XLS\FormObject\dir.stream"]
for dir_path in dir_paths :
try:
dir_stream = file(dir_path, "rb").read()
break
except:
pass
print "[*] Start"
print "[*] File Name : %s" % os.path.basename(dir_path)
print "[*] Decoded..........",
dec_stream = olevba.decompress_stream(dir_stream)
print "Done"
class ProjectSysKind:
# OUT : NamedTuple
Id = 0x0001
size = 0x4
def __init__(self):
self.SIZE = 10
def parseProjectSysKind(self, data, offset):
MEMBER_NAME = ("Proj_SysKind_Id Proj_SysKind_Size SysKind")
MEMBER_PATTERN = "=1H2L"
SysKind = Map("SysKind", data[offset:offset + MapSize(MEMBER_PATTERN)], MEMBER_NAME, MEMBER_PATTERN)
return self._checkProjectSysKind(SysKind)
def parseProjectSysKindEx(self, data, offset):
return self.parseProjectSysKind(data, offset), offset + self.SIZE
def getPlatform(self, syskind):
_EnumSysKind = {
0x00000000 : "16bit Windows Platforms",
0x00000001 : "32bit Windows Platforms",
0x00000002 : "Machintosh Platforms",
0x00000003 : "64bit Windows Platforms"
}
try:
return _EnumSysKind[syskind]
except:
return None
def _checkProjectSysKind(self, SysKind):
if not ( SysKind.Proj_SysKind_Id == self.Id and SysKind.Proj_SysKind_Size == self.size ):
SysKind = None
elif self.getPlatform( SysKind.SysKind ) == None:
SysKind = None
return SysKind
class ProjectLCID:
# OUT : NamedTuple
Id = 0x0002
size = 0x04
lcid = 0x00000409
def __init__(self):
self.SIZE = 10
def parseProjectLCID(self, data, offset):
MEMBER_NAME = ("Proj_LCID_Id Proj_LCID_Size Lcid")
MEMBER_PATTERN = "=1H2L"
Lcid = Map("Lcid", data[offset:offset + MapSize(MEMBER_PATTERN)], MEMBER_NAME, MEMBER_PATTERN)
return self._checkProjectLcid(Lcid)
def parseProjectLCIDEx(self, data, offset):
return self.parseProjectLCID(data, offset), offset + self.SIZE
def _checkProjectLcid(self, Lcid):
if not ( Lcid.Proj_LCID_Id == self.Id and Lcid.Proj_LCID_Size == self.size and Lcid.Lcid == self.lcid ):
Lcid = None
return Lcid
class ProjectLCIDInvoke:
# OUT : NamedTuple
Id = 0x0014
size = 0x4
lcidinvoke = 0x00000409
def __init__(self):
self.SIZE = 10
def parseProjectLCIDInvoke(self, data, offset):
MEMBER_NAME = ("Proj_LCID_Invoke_Id Proj_LCID_Invoke_Size LcidInvoke")
MEMBER_PATTERN = "=1H2L"
LCIDInvoke = Map("LCIDInvoke", data[offset:offset + MapSize(MEMBER_PATTERN)], MEMBER_NAME, MEMBER_PATTERN)
return self._checkProjectLCIDInvoke(LCIDInvoke)
def parseProjectLCIDInvokeEx(self, data, offset):
return self.parseProjectLCIDInvoke(data, offset), offset + self.SIZE
def _checkProjectLCIDInvoke(self, LCIDInvoke):
if not ( LCIDInvoke.Proj_LCID_Invoke_Id == self.Id and LCIDInvoke.Proj_LCID_Invoke_Size == self.size and LCIDInvoke.LcidInvoke == self.lcidinvoke ):
LCIDInvoke = None
return LCIDInvoke
class ProjectCodePage:
# OUT : NamedTuple
Id = 0x0003
size = 0x02
def __init__(self):
self.SIZE = 8
def parseProjectCodePage(self, data, offset):
MEMBER_NAME = ("Proj_CP_Id Proj_CP_Size CodePage")
MEMBER_PATTERN = "=1H1L1H"
CodePage = Map("CodePage", data[offset:offset + MapSize(MEMBER_PATTERN)], MEMBER_NAME, MEMBER_PATTERN)
return self._checkProjectCodePage(CodePage)
def parseProjectCodePageEx(self, data, offset):
return self.parseProjectCodePage(data, offset), offset + self.SIZE
def _checkProjectCodePage(self, CodePage):
if not ( CodePage.Proj_CP_Id == self.Id and CodePage.Proj_CP_Size == self.size ):
CodePage = None
return CodePage
class ProjectName:
# OUT : NamedTuple
Id = 0x0004
MIN_SIZE = 1
MAX_SIZE = 128
def __init__(self):
self.SIZE = 0
def parseProjectName(self, data, offset):
MEMBER_NAME = ("Proj_Name_Id SizeOfProjectName ProjectName")
MEMBER_PATTERN = "=1H1L%ds" % (read32(data, offset + 2))
self.SIZE = MapSize(MEMBER_PATTERN)
ProjectName = Map("ProjectName", data[offset:offset + MapSize(MEMBER_PATTERN)], MEMBER_NAME, MEMBER_PATTERN)
return self._checkProjectProjectName(ProjectName)
def parseProjectNameEx(self, data, offset):
return self.parseProjectName(data, offset), offset + self.SIZE
def _checkProjectProjectName(self, ProjectName):
if not (ProjectName.Proj_Name_Id == self.Id and self.MIN_SIZE <= ProjectName.SizeOfProjectName <= self.MAX_SIZE):
ProjectName = None
return ProjectName
class ProjectDocString:
# OUT : NamedTuple
Id = 0x0005
MAX_SIZE = 2000
reserved = 0x0040
def __init__(self):
self.SIZE = 0
def parseProjectDocString(self, data, offset):
MEMBER_NAME1 = ("Proj_Doc_String_Id SizeOfDocString DocString")
MEMBER_PATTERN1 = "=1H1L%ds" % (read32(data, offset + 2))
size = MapSize(MEMBER_PATTERN1)
tmp1 = Map("tmp1", data[offset:offset + size], MEMBER_NAME1, MEMBER_PATTERN1)
offset += size
self.SIZE += size
MEMBER_NAME2 = ("Reserved SizeOfDocStringUnicode DocStringUnicode")
MEMBER_PATTERN2 = "=1H1L%ds" % (read32(data, offset + 2) * 2)
size = MapSize(MEMBER_PATTERN2)
tmp2 = Map("tmp2", data[offset:offset + size], MEMBER_NAME2, MEMBER_PATTERN2)
self.SIZE += size
DocString = mergeNamedtuple("DocString", tmp1, tmp2)
return self._checkProjectDocString(DocString)
def parseProjectDocStringEx(self, data, offset):
return self.parseProjectDocString(data, offset), offset + self.SIZE
def _checkProjectDocString(self, DocString):
if not ( DocString.Proj_Doc_String_Id == self.Id and DocString.SizeOfDocString <= self.MAX_SIZE and DocString.Reserved == self.reserved ):
DocString = None
return DocString
class ProjectHelpFilePath:
# OUT : NamedTuple
Id = 0x0006
MIN_SIZE1 = 0
MAX_SIZE1 = 260
reserved = 0x003D
def __init__(self):
self.SIZE = 0
def parseProjectHelpFilePath(self, data, offset):
MEMBER_NAME1 = ("Proj_Hlp_FP_Id SizeOfHelpFile1 HelpFile1")
MEMBER_PATTERN1 = "=1H1L%ds" % (read32(data, offset + 2))
size = MapSize(MEMBER_PATTERN1)
tmp1 = Map("tmp1", data[offset:offset + size], MEMBER_NAME1, MEMBER_PATTERN1)
offset += size
self.SIZE += size
MEMBER_NAME2 = ("Reserved SizeOfHelpFile2 HelpFile2")
MEMBER_PATTERN2 = "=1H1L%ds" % (read32(data, offset + 2))
size = MapSize(MEMBER_PATTERN2)
tmp2 = Map("tmp2", data[offset:offset + size], MEMBER_NAME2, MEMBER_PATTERN2)
self.SIZE += size
HelpFilePath = mergeNamedtuple("HelpFilePath", tmp1, tmp2)
return self._checkProjectHelpFilePath(HelpFilePath)
def parseProjectHelpFilePathEx(self, data, offset):
return self.parseProjectHelpFilePath(data, offset), offset + self.SIZE
def _checkProjectHelpFilePath(self, HelpFilePath):
if not (HelpFilePath.Proj_Hlp_FP_Id == self.Id and self.MIN_SIZE1 < HelpFilePath.SizeOfHelpFile1 <= self.MAX_SIZE1 and
HelpFilePath.Reserved == self.reserved and HelpFilePath.SizeOfHelpFile1 == HelpFilePath.SizeOfHelpFile2):
HelpFilePath = None
return HelpFilePath
class ProjectHelpContext:
# OUT : NamedTuple
Id = 0x0007
size = 0x04
def __init__(self):
self.SIZE = 10
def parseProjectHelpContext(self, data, offset):
MEMBER_NAME = ("Proj_Hlp_Context_Id Proj_Hlp_Context_Size HelpContext")
MEMBER_PATTERN = "=1H2L"
HelpContext = Map("HelpContext", data[offset:offset + MapSize(MEMBER_PATTERN)], MEMBER_NAME, MEMBER_PATTERN)
return self._checkProjectHelpContext(HelpContext)
def parseProjectHelpContextEx(self, data, offset):
return self.parseProjectHelpContext(data, offset), offset + self.SIZE
def _checkProjectHelpContext(self, HelpContext):
if not ( HelpContext.Proj_Hlp_Context_Id == self.Id and HelpContext.Proj_Hlp_Context_Size == self.size ):
HelpContext = None
return HelpContext
class ProjectLibFlags:
# OUT : NamedTuple
Id = 0x0008
size = 0x04
flag = 0x0
def __init__(self):
self.SIZE = 10
def parseProjectLibFlags(self, data, offset):
MEMBER_NAME = ("Proj_Lib_Flags_Id Proj_Lib_Flags_Size ProjectLibFlags")
MEMBER_PATTERN = "=1H2L"
LibFlags = Map("LibFlags", data[offset:offset + MapSize(MEMBER_PATTERN)], MEMBER_NAME, MEMBER_PATTERN)
return self._checkProjectLibFlags(LibFlags)
def parseProjectLibFlagsEx(self, data, offset):
return self.parseProjectLibFlags(data, offset), offset + self.SIZE
def _checkProjectLibFlags(self, LibFlags):
if not ( LibFlags.Proj_Lib_Flags_Id == self.Id and LibFlags.Proj_Lib_Flags_Size == self.size and LibFlags.ProjectLibFlags == self.flag ):
LibFlags = None
return LibFlags
class ProjectVersion:
# OUT : NamedTuple
Id = 0x0009
reserved = 0x04
def __init__(self):
self.SIZE = 12
def parseProjectVersion(self, data, offset):
MEMBER_NAME = ("Proj_Ver_Id Reserved VersionMajor VersionMinor")
MEMBER_PATTERN = "=1H2L1H"
Version = Map("Version", data[offset:offset + MapSize(MEMBER_PATTERN)], MEMBER_NAME, MEMBER_PATTERN)
return self._checkProjectVersion(Version)
def parseProjectVersionEx(self, data, offset):
return self.parseProjectVersion(data, offset), offset + self.SIZE
def _checkProjectVersion(self, Version):
if not (Version.Proj_Ver_Id == self.Id and Version.Reserved == self.reserved ):
Version = None
return Version
class ProjectConstants:
# OUT : NamedTuple
Id = 0x000C
MAX_SIZE = 1015
reserved = 0x003C
def __init__(self):
self.SIZE = 0
def parseProjectConstants(self, data, offset):
MEMBER_NAME1 = ("Proj_Constants_Id SizeOfConstants Constants")
MEMBER_PATTERN1 = "=1H1L%ds" % (read32(data, offset + 2))
size = MapSize(MEMBER_PATTERN1)
tmp1 = Map("tmp1", data[offset:offset + size], MEMBER_NAME1, MEMBER_PATTERN1)
offset += size
self.SIZE += size
MEMBER_NAME2 = ("Reserved SizeOfConstantsUnicode ConstantsUnicode")
MEMBER_PATTERN2 = "=1H1L%ds" % (read32(data, offset + 2) * 2)
size = MapSize(MEMBER_PATTERN2)
tmp2 = Map("tmp2", data[offset:offset + size], MEMBER_NAME2, MEMBER_PATTERN2)
self.SIZE += size
Constants = mergeNamedtuple("Constants", tmp1, tmp2)
return self._checkProjectConstants(Constants)
def parseProjectConstantsEx(self, data, offset):
return self.parseProjectConstants(data, offset), offset + self.SIZE
def _checkProjectConstants(self, Constants):
if not ( Constants.Proj_Constants_Id == self.Id and Constants.SizeOfConstants <= self.MAX_SIZE and Constants.Reserved == self.reserved ):
Constants = None
return Constants
class ProjectInformation:
# OUT : NamedTuple
def __init__(self):
self.SIZE = 0
def _getProjectSysKind(self, data, offset):
obj = ProjectSysKind()
out, offset = obj.parseProjectSysKindEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def _getProjectLCID(self, data, offset):
obj = ProjectLCID()
out, offset = obj.parseProjectLCIDEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def _getProjectLCIDInvoke(self, data, offset):
obj = ProjectLCIDInvoke()
out, offset = obj.parseProjectLCIDInvokeEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def _getProjectCodePage(self, data, offset):
obj = ProjectCodePage()
out, offset = obj.parseProjectCodePageEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def _getProjectName(self, data, offset):
obj = ProjectName()
out, offset = obj.parseProjectNameEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def _getProjectDocString(self, data, offset):
obj = ProjectDocString()
out, offset = obj.parseProjectDocStringEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def _getProjectHelpFilePath(self, data, offset):
obj = ProjectHelpFilePath()
out, offset = obj.parseProjectHelpFilePathEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def _getProjectHelpContext(self, data, offset):
obj = ProjectHelpContext()
out, offset = obj.parseProjectHelpContextEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def _getProjectLibFlags(self, data, offset):
obj = ProjectLibFlags()
out, offset = obj.parseProjectLibFlagsEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def _getProjectVersion(self, data, offset):
obj = ProjectVersion()
out, offset = obj.parseProjectVersionEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def _getProjectConstants(self, data, offset):
obj = ProjectConstants()
out, offset = obj.parseProjectConstantsEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def parseProjectInformation(self, data, offset):
print "[*] InformationRecord",
SysKindRecord, offset = self._getProjectSysKind(data, offset)
LcidRecord, offset = self._getProjectLCID(data, offset)
LcidInvokeRecord, offset = self._getProjectLCIDInvoke(data, offset)
CodePageRecord, offset = self._getProjectCodePage(data, offset)
NameRecord, offset = self._getProjectName(data, offset)
DocStringRecord, offset = self._getProjectDocString(data, offset)
HelpFilePathRecord, offset = self._getProjectHelpFilePath(data, offset)
HelpContextRecord, offset = self._getProjectHelpContext(data, offset)
LibFlagsRecord, offset = self._getProjectLibFlags(data, offset)
VersionRecord, offset = self._getProjectVersion(data, offset)
ConstantsRecord, offset = self._getProjectConstants(data, offset)
PROJ_INFO_MEMBER = ["SysKindRecord", "LcidRecord", "LcidInvokeRecord", "CodePageRecord", "NameRecord",
"DocStringRecord", "HelpFilePathRecord", "HelpContextRecord", "LibFlagsRecord",
"VersionRecord", "ConstantsRecord"]
ProjectInfo = newMap("ProjectInfo", PROJ_INFO_MEMBER)
out = None
out = ProjectInfo(SysKindRecord=SysKindRecord, LcidRecord=LcidRecord, LcidInvokeRecord=LcidInvokeRecord,
CodePageRecord=CodePageRecord, NameRecord=NameRecord, DocStringRecord=DocStringRecord,
HelpFilePathRecord=HelpFilePathRecord, HelpContextRecord=HelpContextRecord,
LibFlagsRecord=LibFlagsRecord, VersionRecord=VersionRecord, ConstantsRecord=ConstantsRecord)
return self._checkProjectInformation(out)
def parseProjectInformationEx(self, data, offset):
return self.parseProjectInformation(data, offset), offset + self.SIZE
def _checkProjectInformation(self, out):
if out == None:
print "..........Error"
else:
print "..........Done"
return out
class ReferenceOriginal:
# OUT : NamedTuple
def __init__(self):
self.SIZE = 0
def parseReferenceOriginal(self, data, offset):
MEMBER_NAME = ("Ref_Original_Id SizeOfLibidOriginal LibidOriginal")
MEMBER_PATTERN = "=1H1L%ds" % (read32(data, offset + 2))
size = MapSize(MEMBER_PATTERN)
ReferenceOriginal = Map("ReferenceOriginal", data[offset:offset + size], MEMBER_NAME, MEMBER_PATTERN)
self.SIZE += size
return self._checkReferenceOriginal(ReferenceOriginal)
def parseReferenceOriginalEx(self, data, offset):
return self.parseReferenceOriginal(data, offset), offset + self.SIZE
def _checkReferenceOriginal(self, ReferenceOriginal):
if not (ReferenceOriginal.Ref_Original_Id == 0x0033):
ReferenceOriginal = None
return ReferenceOriginal
class ReferenceControl:
# OUT : NamedTuple
Id = 0x002F
reserved1 = 0x00
reserved2 = 0x00
reserved3 = 0x0030
reserved4 = 0x00
reserved5 = 0x00
def __init__(self):
self.SIZE = 0
def _getReferenceOriginal(self, data, offset):
obj = ReferenceOriginal()
out, offset = obj.parseReferenceOriginalEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def _getReferenceName(self, data, offset):
obj = ReferenceName()
out, offset = obj.parseReferenceNameEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def parseReferenceControl(self, data, offset):
OriginalRecord, offset = self._getReferenceOriginal(data, offset)
MEMBER_NAME1 = ("Ref_Ctrl_Id SizeTwiddled SizeOfLibidTwiddled LibidTwiddled Reserved1 Reserved2")
MEMBER_PATTERN1 = "=1H2L%ds1L1H" % (read32(data, offset + 6))
size = MapSize(MEMBER_PATTERN1)
tmp1 = Map("tmp1", data[offset:offset + size], MEMBER_NAME1, MEMBER_PATTERN1)
offset += size
self.SIZE += size
ReferenceControl = mergeNamedtuple("ReferenceControl", OriginalRecord, tmp1)
NamedRecordExtended, offset = self._getReferenceName(data, offset)
ReferenceControl = mergeNamedtuple("ReferenceControl", ReferenceControl, NamedRecordExtended)
MEMBER_NAME2 = ("Reserved3 SizeExtended SizeOfLibidExtended LibidExtended Reserved4 Reserved5 OriginalTypeLib Cookie")
MEMBER_PATTERN2 = "=1H2L%ds1L1H16s1L" % (read32(data, offset + 6))
size = MapSize(MEMBER_PATTERN2)
tmp2 = Map("tmp2", data[offset:offset + size], MEMBER_NAME2, MEMBER_PATTERN2)
self.SIZE += size
ReferenceControl = mergeNamedtuple("ReferenceControl", ReferenceControl, tmp2)
return self._checkReferenceControl(ReferenceControl)
def parseReferenceControlEx(self, data, offset):
return self.parseReferenceControl(data, offset), offset + self.SIZE
def parse(self, data, offset):
return self.parseReferenceControlEx(data, offset)
def _checkReferenceControl(self, ReferenceControl):
if not (ReferenceControl.Ref_Ctrl_Id == self.Id and ReferenceControl.Reserved1 == self.reserved1 and
ReferenceControl.Reserved2 == self.reserved2 and ReferenceControl.Reserved3 == self.reserved3 and
ReferenceControl.Reserved4 == self.reserved4 and ReferenceControl.Reserved5 == self.reserved5):
ReferenceControl = None
return ReferenceControl
class ReferenceRegistered:
# OUT : NamedTuple
Id = 0x000D
reserved1 = 0x00
reserved2 = 0x00
def __init__(self):
self.SIZE = 0
def parseReferenceRegistered(self, data, offset):
MEMBER_NAME = ("Ref_Reg_Id Size SizeOfLibid Libid Reserved1 Reserved2")
MEMBER_PATTERN = "=1H2L%ds1L1H" % (read32(data, offset + 6))
size = MapSize(MEMBER_PATTERN)
self.SIZE += size
ReferenceRegistered = Map("ReferenceRegistered", data[offset:offset + size], MEMBER_NAME, MEMBER_PATTERN)
return self._checkReferenceRegistered(ReferenceRegistered)
def parseReferenceRegisteredEx(self, data, offset):
return self.parseReferenceRegistered(data, offset), offset + self.SIZE
def parse(self, data, offset):
return self.parseReferenceRegisteredEx(data, offset)
def _checkReferenceRegistered(self, ReferenceRegistered):
if not (ReferenceRegistered.Ref_Reg_Id == self.Id and ReferenceRegistered.Reserved1 == self.reserved1 and
ReferenceRegistered.Reserved2 == self.reserved2):
ReferenceRegistered = None
return ReferenceRegistered
class ReferenceProject:
# OUT : NamedTuple
Id = 0x000E
def __init__(self):
self.SIZE = 0
def parseReferenceProject(self, data, offset):
MEMBER_NAME1 = ("Ref_Proj_Id Size SizeOfLibidAbsolute LibidAbsolute")
MEMBER_PATTERN1 = "=1H2L%ds" % (read32(data, offset + 6))
size = MapSize(MEMBER_PATTERN1)
tmp1 = Map("tmp1", data[offset:offset + size], MEMBER_NAME1, MEMBER_PATTERN1)
offset += size
self.SIZE += size
MEMBER_NAME2 = ("SizeOfLibidRelative LibidRelative MajorVersion MinorVersion")
MEMBER_PATTERN2 = "=1L%ds1L1H" % (read32(data, offset))
size = MapSize(MEMBER_PATTERN2)
tmp2 = Map("tmp2", data[offset:offset + size], MEMBER_NAME2, MEMBER_PATTERN2)
self.SIZE += size
ReferenceProject = mergeNamedtuple("ReferenceProject", tmp1, tmp2)
return self._checkReferenceProject(ReferenceProject)
def parseReferenceProjectEx(self, data, offset):
return self.parseReferenceProject(data, offset), offset + self.SIZE
def parse(self, data, offset):
return self.parseReferenceProjectEx(data, offset)
def _checkReferenceProject(self, ReferenceProject):
if not (ReferenceProject.Ref_Proj_Id == self.Id):
ReferenceProject = None
return ReferenceProject
class ReferenceName:
# OUT : NamedTuple
Id = 0x0016
reserved = 0x003E
def __init__(self):
self.SIZE = 0
def parseReferenceName(self, data, offset):
MEMBER_NAME1 = ("Ref_Name_Id SizeOfName Name")
MEMBER_PATTERN1 = "=1H1L%ds" % (read32(data, offset + 2))
size = MapSize(MEMBER_PATTERN1)
tmp1 = Map("tmp1", data[offset:offset + size], MEMBER_NAME1, MEMBER_PATTERN1)
offset += size
self.SIZE += size
MEMBER_NAME2 = ("Reserved SizeOfNameUnicode NameUnicode")
MEMBER_PATTERN2 = "=1H1L%ds" % (read32(data, offset + 2))
size = MapSize(MEMBER_PATTERN2)
tmp2 = Map("tmp2", data[offset:offset + size], MEMBER_NAME2, MEMBER_PATTERN2)
self.SIZE += size
ReferenceName = mergeNamedtuple("ReferenceName", tmp1, tmp2)
return self._checkProjectReferenceName(ReferenceName)
def parseReferenceNameEx(self, data, offset):
return self.parseReferenceName(data, offset), offset + self.SIZE
def _checkProjectReferenceName(self, ReferenceName):
if not (ReferenceName.Ref_Name_Id == self.Id and ReferenceName.Reserved == self.reserved):
ReferenceName = None
return ReferenceName
class Reference:
# OUT : NamedTuple
Id = 0x000F
def __init__(self):
self.SIZE = 0
def _getReferenceName(self, data, offset):
obj = ReferenceName()
out, offset = obj.parseReferenceNameEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def _getReferenceRecord(self, data, offset):
record_type = read16(data, offset)
if record_type in [0x002F, 0x0033]:
obj = ReferenceControl()
elif record_type in [0x000D]:
obj = ReferenceRegistered()
elif record_type in [0x000E]:
obj = ReferenceProject()
else:
obj = None
out, offset = obj.parse(data, offset)
self.SIZE += obj.SIZE
return out, offset
def parseReference(self, data, offset):
NameRecord, offset = self._getReferenceName(data, offset)
ReferenceRecord, offset = self._getReferenceRecord(data, offset)
return newMap("Reference", ["NameRecord", "ReferenceRecord"])(NameRecord=NameRecord, ReferenceRecord=ReferenceRecord)
def parseReferenceEx(self, data, offset):
return self.parseReference(data, offset), offset + self.SIZE
def isEnd(self, data, offset):
if read16(data, offset) == self.Id:
return True
else:
return False
class ProjectReferences:
# OUT : List
def __init__(self):
self.SIZE = 0
def _getReference(self, data, offset):
obj = Reference()
out, offset = obj.parseReferenceEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def _chkEndReference(self, data, offset):
obj = Reference()
return obj.isEnd(data, offset)
def parseProjectReferences(self, data, offset):
print "[*] ReferenceRecord",
out = []
while offset < len(data):
if self._chkEndReference(data, offset) == True:
break
tmp, offset = self._getReference(data, offset)
out.append(tmp)
return self._checkProjectReference(out)
def parseProjectReferencesEx(self, data, offset):
return self.parseProjectReferences(data, offset), offset + self.SIZE
def _checkProjectReference(self, out):
if len(out) == 0:
print "..........Error"
else:
print "..........Done"
return out
class ProjectCookie:
# OUT : NamedTuple
Id = 0x0013
size = 0x00000002
def __init__(self):
self.SIZE = 8
def parseProjectCookie(self, data, offset):
MEMBER_NAME = ("Proj_Cookie_Id Size Cookie")
MEMBER_PATTERN = "=1H1L1H"
ProjCookie = Map("ProjCookie", data[offset:offset + MapSize(MEMBER_PATTERN)], MEMBER_NAME, MEMBER_PATTERN)
return self._checkProjectCookie(ProjCookie)
def parseProjectCookieEx(self, data, offset):
return self.parseProjectCookie(data, offset), offset + self.SIZE
def _checkProjectCookie(self, ProjCookie):
if not ( ProjCookie.Proj_Cookie_Id == self.Id and ProjCookie.Size == self.size ):
ProjCookie = None
return ProjCookie
class ModuleName:
# OUT : NamedTuple
Id = 0x0019
def __init__(self):
self.SIZE = 0
def Enable(self, data, offset):
if read16(data, offset) == self.Id:
return True
else:
return False
def parseModuleName(self, data, offset):
MEMBER_NAME = ("Mod_Name_Id SizeOfModuleName ModuleName")
MEMBER_PATTERN = "=1H1L%ds" % read32(data, offset + 2)
size = MapSize(MEMBER_PATTERN)
mod_name = Map("Mod_Name", data[offset:offset + size], MEMBER_NAME, MEMBER_PATTERN)
self.SIZE += size
return self._checkModuleName(mod_name)
def parseModuleNameEx(self, data, offset):
return self.parseModuleName(data, offset), offset + self.SIZE
def _checkModuleName(self, mod_name):
if not ( mod_name.Mod_Name_Id == self.Id ):
mod_name = None
return mod_name
class ModuleNameUnicode:
# OUT : NamedTuple
Id = 0x0047
def __init__(self):
self.SIZE = 0
def Enable(self, data, offset):
if read16(data, offset) == self.Id:
return True
else:
return False
def parseModuleNameUnicode(self, data, offset):
MEMBER_NAME = ("Mod_Name_Uni_Id SizeOfModuleNameUnicode ModuleNameUnicode")
MEMBER_PATTERN = "=1H1L%ds" % read32(data, offset + 2)
size = MapSize(MEMBER_PATTERN)
mod_name = Map("Mod_NameUnicode", data[offset:offset + size], MEMBER_NAME, MEMBER_PATTERN)
self.SIZE += size
return self._checkModuleNameUnicode(mod_name)
def parseModuleNameUnicodeEx(self, data, offset):
return self.parseModuleNameUnicode(data, offset), offset + self.SIZE
def _checkModuleNameUnicode(self, mod_name):
if not ( mod_name.Mod_Name_Uni_Id == self.Id ):
mod_name = None
return mod_name
class ModuleStreamName:
# OUT : NamedTuple
Id = 0x001A
reserved = 0x0032
def __init__(self):
self.SIZE = 0
def Enable(self, data, offset):
if read16(data, offset) == self.Id:
return True
else:
return False
def parseModuleStreamName(self, data, offset):
MEMBER_NAME1 = ("Mod_Stream_Name_Id SizeOfStreamName StreamName")
MEMBER_PATTERN1 = "=1H1L%ds" % read32(data, offset + 2)
size = MapSize(MEMBER_PATTERN1)
tmp1 = Map("tmp1", data[offset:offset + size], MEMBER_NAME1, MEMBER_PATTERN1)
offset += size
self.SIZE += size
MEMBER_NAME2 = ("Reserved SizeOfStreamNameUnicode StreamNameUnicode")
MEMBER_PATTERN2 = "=1H1L%ds" % read32(data, offset + 2)
size = MapSize(MEMBER_PATTERN2)
tmp2 = Map("tmp2", data[offset:offset + size], MEMBER_NAME2, MEMBER_PATTERN2)
offset += size
self.SIZE += size
Mod_StreamName = mergeNamedtuple("Mod_StreamName", tmp1, tmp2)
return self._checkModuleStreamName(Mod_StreamName)
def parseModuleStreamNameEx(self, data, offset):
return self.parseModuleStreamName(data, offset), offset + self.SIZE
def _checkModuleStreamName(self, Mod_StreamName):
if not ( Mod_StreamName.Mod_Stream_Name_Id == self.Id and Mod_StreamName.Reserved == self.reserved ):
Mod_StreamName = None
return Mod_StreamName
class ModuleDocString:
# OUT : NamedTuple
Id = 0x001C
reserved = 0x0048
def __init__(self):
self.SIZE = 0
def Enable(self, data, offset):
if read16(data, offset) == self.Id:
return True
else:
return False
def parseModuleDocString(self, data, offset):
MEMBER_NAME1 = ("Mod_Doc_String_Id SizeOfDocString DocString")
MEMBER_PATTERN1 = "=1H1L%ds" % read32(data, offset + 2)
size = MapSize(MEMBER_PATTERN1)
tmp1 = Map("tmp1", data[offset:offset + size], MEMBER_NAME1, MEMBER_PATTERN1)
offset += size
self.SIZE += size
MEMBER_NAME2 = ("Reserved SizeOfDocStringUnicode DocStringUnicode")
MEMBER_PATTERN2 = "=1H1L%ds" % read32(data, offset + 2)
size = MapSize(MEMBER_PATTERN2)
tmp2 = Map("tmp2", data[offset:offset + size], MEMBER_NAME2, MEMBER_PATTERN2)
offset += size
self.SIZE += size
Mod_DocString = mergeNamedtuple("Mod_DocString", tmp1, tmp2)
return self._checkModuleDocString(Mod_DocString)
def parseModuleDocStringEx(self, data, offset):
return self.parseModuleDocString(data, offset), offset + self.SIZE
def _checkModuleDocString(self, Mod_DocString):
if not ( Mod_DocString.Mod_Doc_String_Id == self.Id and Mod_DocString.Reserved == self.reserved ):
Mod_DocString = None
return Mod_DocString
class ModuleOffset:
# OUT : NamedTuple
Id = 0x0031
size = 0x00000004
def __init__(self):
self.SIZE = 10
def Enable(self, data, offset):
if read16(data, offset) == self.Id:
return True
else:
return False
def parseModuleOffset(self, data, offset):
MEMBER_NAME = ("Mod_Offset_Id Mod_Offset_Size TextOffset")
MEMBER_PATTERN = "=1H2L"
mod_offset = Map("Mod_Offset", data[offset:offset + MapSize(MEMBER_PATTERN)], MEMBER_NAME, MEMBER_PATTERN)
return self._checkModuleOffset(mod_offset)
def parseModuleOffsetEx(self, data, offset):
return self.parseModuleOffset(data, offset), offset + self.SIZE
def _checkModuleOffset(self, mod_offset):
if not (mod_offset.Mod_Offset_Id == self.Id and mod_offset.Mod_Offset_Size == self.size):
mod_offset = None
return mod_offset
class ModuleHelpContext:
# OUT : NamedTuple
Id = 0x001E
size = 0x00000004
def __init__(self):
self.SIZE = 10
def Enable(self, data, offset):
if read16(data, offset) == self.Id:
return True
else:
return False
def parseModuleHelpContext(self, data, offset):
MEMBER_NAME = ("Mod_Hlp_Context_Id Mod_Hlp_Context_Size HelpContext")
MEMBER_PATTERN = "=1H2L"
Mod_HlpContext = Map("Mod_HlpContext", data[offset:offset + MapSize(MEMBER_PATTERN)], MEMBER_NAME, MEMBER_PATTERN)
return self._checkModuleHelpContext(Mod_HlpContext)
def parseModuleHelpContextEx(self, data, offset):
return self.parseModuleHelpContext(data, offset), offset + self.SIZE
def _checkModuleHelpContext(self, Mod_HlpContext):
if not (Mod_HlpContext.Mod_Hlp_Context_Id == self.Id and Mod_HlpContext.Mod_Hlp_Context_Size == self.size):
Mod_HlpContext = None
return Mod_HlpContext
class ModuleCookie:
# OUT : NamedTuple
Id = 0x002C
size = 0x00000002
cookie = 0xFFFF
def __init__(self):
self.SIZE = 8
def Enable(self, data, offset):
if read16(data, offset) == self.Id:
return True
else:
return False
def parseModuleCookie(self, data, offset):
MEMBER_NAME = ("Mod_Cookie_Id Mod_Cookie_Size Cookie")
MEMBER_PATTERN = "=1H2L"
Mod_Cookie = Map("Mod_Cookie", data[offset:offset + MapSize(MEMBER_PATTERN)], MEMBER_NAME, MEMBER_PATTERN)
return self._checkModuleCookie(Mod_Cookie)
def parseModuleCookieEx(self, data, offset):
return self.parseModuleCookie(data, offset), offset + self.SIZE
def _checkModuleCookie(self, Mod_Cookie):
if not (Mod_Cookie.Mod_Cookie_Id == self.Id and Mod_Cookie.Mod_Cookie_Size == self.size and Mod_Cookie.Cookie == self.cookie):
Mod_Cookie = None
return Mod_Cookie
class ModuleType:
# OUT : NamedTuple
Id = [0x0021, 0x0022]
reserved = 0x00000000
def __init__(self):
self.SIZE = 6
def Enable(self, data, offset):
if read16(data, offset) in self.Id:
return True
else:
return False
def parseModuleType(self, data, offset):
MEMBER_NAME = ("Mod_Type_Id Reserved")
MEMBER_PATTERN = "=1H1L"
Mod_Type = Map("Mod_Type", data[offset:offset + MapSize(MEMBER_PATTERN)], MEMBER_NAME, MEMBER_PATTERN)
return self._checkModuleType(Mod_Type)
def parseModuleTypeEx(self, data, offset):
return self.parseModuleType(data, offset), offset + self.SIZE
def _checkModuleType(self, Mod_Type):
if not (Mod_Type.Reserved == self.reserved and Mod_Type.Mod_Type_Id in self.Id):
Mod_Type = None
return Mod_Type
class ModuleReadOnly:
# OUT : NamedTuple
Id = 0x0025
reserved = 0x00000000
def __init__(self):
self.SIZE = 6
def Enable(self, data, offset):
if read16(data, offset) == self.Id:
return True
else:
return False
def parseModuleReadOnly(self, data, offset):
MEMBER_NAME = ("Mod_RO_Id Reserved")
MEMBER_PATTERN = "=1H1L"
Mod_ReadOnly = Map("Mod_ReadOnly", data[offset:offset + MapSize(MEMBER_PATTERN)], MEMBER_NAME, MEMBER_PATTERN)
return self._checkModuleReadOnly(Mod_ReadOnly)
def parseModuleReadOnlyEx(self, data, offset):
return self.parseModuleReadOnly(data, offset), offset + self.SIZE
def _checkModuleReadOnly(self, Mod_ReadOnly):
if not (Mod_ReadOnly.Reserved == self.reserved and Mod_ReadOnly.Mod_RO_Id == self.Id):
Mod_ReadOnly = None
return Mod_ReadOnly
class ModulePrivate:
# OUT : NamedTuple
Id = 0x0028
reserved = 0x00000000
def __init__(self):
self.SIZE = 6
def Enable(self, data, offset):
if read16(data, offset) == self.Id:
return True
else:
return False
def parseModulePrivate(self, data, offset):
MEMBER_NAME = ("Mod_Private_Id Reserved")
MEMBER_PATTERN = "=1H1L"
Mod_Private = Map("Mod_Private", data[offset:offset + MapSize(MEMBER_PATTERN)], MEMBER_NAME, MEMBER_PATTERN)
return self._checkModulePrivate(Mod_Private)
def parseModulePrivateEx(self, data, offset):
return self.parseModulePrivate(data, offset), offset + self.SIZE
def _checkModulePrivate(self, Mod_Private):
if not (Mod_Private.Reserved == self.reserved and Mod_Private.Mod_Private_Id == self.Id):
Mod_Private = None
return Mod_Private
class Module:
terminator = 0x002B
reserved = 0x00000000
def __init__(self):
self.SIZE = 0
def _getModuleName(self, data, offset):
out = None
obj = ModuleName()
if obj.Enable(data, offset) == True:
out, offset = obj.parseModuleNameEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def _getModuleNameUnicode(self, data, offset):
out = None
obj = ModuleNameUnicode()
if obj.Enable(data, offset) == True:
out, offset = obj.parseModuleNameUnicodeEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def _getModuleStreamName(self, data, offset):
out = None
obj = ModuleStreamName()
if obj.Enable(data, offset) == True:
out, offset = obj.parseModuleStreamNameEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def _getModuleDocString(self, data, offset):
out = None
obj = ModuleDocString()
if obj.Enable(data, offset) == True:
out, offset = obj.parseModuleDocStringEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def _getModuleOffset(self, data, offset):
out = None
obj = ModuleOffset()
if obj.Enable(data, offset) == True:
out, offset = obj.parseModuleOffsetEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def _getModuleHelpContext(self, data, offset):
out = None
obj = ModuleHelpContext()
if obj.Enable(data, offset) == True:
out, offset = obj.parseModuleHelpContextEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def _getModuleCookie(self, data, offset):
out = None
obj = ModuleCookie()
if obj.Enable(data, offset) == True:
out, offset = obj.parseModuleCookieEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def _getModuleType(self, data, offset):
out = None
obj = ModuleType()
if obj.Enable(data, offset) == True:
out, offset = obj.parseModuleTypeEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def _getModuleReadOnly(self, data, offset):
out = None
obj = ModuleReadOnly()
if obj.Enable(data, offset) == True:
out, offset = obj.parseModuleReadOnlyEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def _getModulePrivate(self, data, offset):
out = None
obj = ModulePrivate()
if obj.Enable(data, offset) == True:
out, offset = obj.parseModulePrivateEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def parseModule(self, data, offset):
Modules = newMap("Modules", [])()
NameRecord, offset = self._getModuleName(data, offset)
if NameRecord != None:
Modules = addNamedtuple("Modules", Modules, "NameRecord", NameRecord)
NameUnicodeRecord, offset = self._getModuleNameUnicode(data, offset)
if NameUnicodeRecord != None:
Modules = addNamedtuple("Modules", Modules, "NameUnicodeRecord", NameUnicodeRecord)
StreamNameRecord, offset = self._getModuleStreamName(data, offset)
if StreamNameRecord != None:
Modules = addNamedtuple("Modules", Modules, "StreamNameRecord", StreamNameRecord)
DocStringRecord, offset = self._getModuleDocString(data, offset)
if DocStringRecord != None:
Modules = addNamedtuple("Modules", Modules, "DocStringRecord", DocStringRecord)
OffsetRecord, offset = self._getModuleOffset(data, offset)
if OffsetRecord != None:
Modules = addNamedtuple("Modules", Modules, "OffsetRecord", OffsetRecord)
HelpContextRecord, offset = self._getModuleHelpContext(data, offset)
if HelpContextRecord != None:
Modules = addNamedtuple("Modules", Modules, "HelpContextRecord", HelpContextRecord)
CookieRecord, offset = self._getModuleCookie(data, offset)
if CookieRecord != None:
Modules = addNamedtuple("Modules", Modules, "CookieRecord", CookieRecord)
TypeRecord, offset = self._getModuleType(data, offset)
if TypeRecord != None:
Modules = addNamedtuple("Modules", Modules, "TypeRecord", TypeRecord)
ReadOnlyRecord, offset = self._getModuleReadOnly(data, offset)
if ReadOnlyRecord != None:
Modules = addNamedtuple("Modules", Modules, "ReadOnlyRecord", ReadOnlyRecord)
PrivateRecord, offset = self._getModulePrivate(data, offset)
if PrivateRecord != None:
Modules = addNamedtuple("Modules", Modules, "PrivateRecord", PrivateRecord)
Terminator, offset = read16Ex(data, offset)
Modules = addNamedtuple("Modules", Modules, "Terminator", Terminator)
self.SIZE += 2
Reserved = read32(data, offset)
Modules = addNamedtuple("Modules", Modules, "Reserved", Reserved)
self.SIZE += 4
return self._checkModule(Modules)
def parseModuleEx(self, data, offset):
return self.parseModule(data, offset), offset + self.SIZE
def _checkModule(self, Modules):
if not ( Modules.Terminator == self.terminator and Modules.Reserved == self.reserved ):
Modules = None
return Modules
class ProjectModules:
Id = 0x000F
def __init__(self):
self.SIZE = 0
def _getProjectCookie(self, data, offset):
obj = ProjectCookie()
out, offset = obj.parseProjectCookieEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def _getModule(self, data, offset):
obj = Module()
out, offset = obj.parseModuleEx(data, offset)
self.SIZE += obj.SIZE
return out, offset
def parseProjectModules(self, data, offset):
print "[*] ModulesRecord",
MEMBER_NAME = ("Proj_Mod_Id Proj_Mod_Size Count")
MEMBER_PATTERN = "=1H1L1H"
size = MapSize(MEMBER_PATTERN)
tmp1 = Map("tmp1", data[offset:offset + size], MEMBER_NAME, MEMBER_PATTERN)
offset += size
self.SIZE += size
ProjectCookie, offset = self._getProjectCookie(data, offset)
tmp2 = addNamedtuple("tmp2", tmp1, "ProjectCookieRecord", ProjectCookie)
Modules = []
for i in xrange(tmp1.Count):
mod, offset = self._getModule(data, offset)
Modules.append(mod)
ProjModules = addNamedtuple("ProjModules", tmp2, "Modules", Modules)
return self._checkProjectModules(ProjModules)
def parseProjectModulesEx(self, data, offset):
return self.parseProjectModules(data, offset), offset + self.SIZE
def _checkProjectModules(self, ProjModules):
if not ( ProjModules.Proj_Mod_Id == self.Id and ProjModules.Proj_Mod_Size == 0x00000002 ):
ProjModules = None
print "..........Error"
else:
print "..........Done"
return ProjModules
def getProjectInformation(data, offset):
obj = ProjectInformation()
return obj.parseProjectInformationEx(data, offset)
def getProjectReferences(data, offset):
obj = ProjectReferences()
return obj.parseProjectReferencesEx(data, offset)
def getProjectModules(data, offset):
obj = ProjectModules()
return obj.parseProjectModulesEx(data, offset)
def PrintLog(dirStream):
print "[Info] Project Name : %s" % dirStream.InformationRecord.NameRecord.ProjectName
reference = dirStream.ReferencesRecord
for i in xrange(len(reference)):
print "[Info] Reference : %s" % (reference[i].NameRecord.Name)
modules = dirStream.ModulesRecord.Modules
for mod in modules:
name = mod.NameRecord.ModuleName
offset = mod.OffsetRecord.TextOffset
print "[Info] Modules Name : %s (Offset : 0x%x)" % (name, offset)
print "[*] Parse dir Stream "
offset = 0
infoRecord, offset = getProjectInformation(dec_stream, offset)
refRecord, offset = getProjectReferences(dec_stream, offset)
modRecord, offset = getProjectModules(dec_stream, offset)
terminator, offset = read16Ex(dec_stream, offset)
reserved, offset = read32Ex(dec_stream, offset)
dirStream = newMap("dirStream", ["InformationRecord", "ReferencesRecord", "ModulesRecord", "Terminator", "Reserved"])
dirStream = dirStream(InformationRecord=infoRecord, ReferencesRecord=refRecord, ModulesRecord=modRecord, Terminator=terminator,
Reserved=reserved)
if offset != len(dec_stream):
print "[*] [ERROR] dirStream.parse() is not complete"
print ""
PrintLog(dirStream)
code_page = dirStream.InformationRecord.CodePageRecord.CodePage
codec = "cp%d" % code_page
print "[Codec] %s" % codec
def PrintLog2(dirStream):
print "[Info] Project Name : %s" % dirStream.InformationRecord.NameRecord.ProjectName
reference = dirStream.ReferencesRecord
for i in xrange(len(reference)):
print "[Info] Reference : %s" % (reference[i].NameRecord.Name)
modules = dirStream.ModulesRecord.Modules
for mod in modules:
name = mod.NameRecord.ModuleName
offset = mod.OffsetRecord.TextOffset
print "[Info] Modules Name : %s (Offset : 0x%x)" % (name.decode(codec), offset)
PrintLog2(dirStream)
class moduleStream:
def __init__(self, mod_dir, name, offset):
self.mod_dir = mod_dir
self.fname = name
self.start_offset = offset
self.fullname = self.mod_dir + os.sep + self.fname + ".stream"
self.data = file(self.fullname, "rb").read()
def parse(self):
out = None
if len(self.data) == 0:
print "[ERROR] %s : Read Failed" % self.fname
return out
print "[*] Start"
print "[*] File Name : %s" % self.fname
print "[*] Decoded..........",
out = olevba.decompress_stream(self.data[self.start_offset:])
print "Done\n"
return out
mod_dir = r"C:\Users\amanaksu\Dropbox\Sample_Windows\###. CFBF-XLS\FormObject"
result = []
modules = dirStream.ModulesRecord.Modules
for mod in modules:
name = mod.NameRecord.ModuleName.decode(codec)
tmp = os.path.join(mod_dir, "%s.stream" % name)
if os.path.isfile(tmp) == True:
offset = mod.OffsetRecord.TextOffset
obj = moduleStream(mod_dir, name, offset)
out = obj.parse()
result.append(out)
print result[-1].decode(codec)
댓글
댓글 쓰기