Attribute VB_Name = "modPEInfo"
'' File Information Module for PSlHardCodedString.bas
'' (c) 2019-2019 by wanfu (Last modified on 2019.12.14)

'#Uses "modCommon.bas"

Option Explicit

'Android
Private Enum Android_RES_TYPE
    'RES_NULL_TYPE               = &H0000
    RES_STRING_POOL_TYPE        = &H0001
    RES_TABLE_TYPE              = &H0002
    RES_XML_TYPE                = &H0003
    'Chunk types In RES_XML_TYPE
    'RES_XML_FIRST_CHUNK_TYPE    = &H0100
    'RES_XML_START_NAMESPACE_TYPE= &H0100
    'RES_XML_END_NAMESPACE_TYPE  = &H0101
    'RES_XML_START_ELEMENT_TYPE  = &H0102
    'RES_XML_END_ELEMENT_TYPE    = &H0103
    'RES_XML_CDATA_TYPE          = &H0104
    'RES_XML_LAST_CHUNK_TYPE     = &H017F
    'This contains a uint32_t Array mapping strings In the String
    'pool back To resource identifiers.  It Is Optional.
    'RES_XML_RESOURCE_MAP_TYPE   = &H0180
    'Chunk types In RES_TABLE_TYPE
    'RES_TABLE_PACKAGE_TYPE      = &H0200
    'RES_TABLE_TYPE_TYPE         = &H0201
    'RES_TABLE_TYPE_SPEC_TYPE    = &H0202
    'RES_TABLE_LIBRARY_TYPE      = &H0203
End Enum

Private Type ResChunk_header
	RES_TYPE		As Integer	'Type identifier for this chunk
	headerSize		As Integer	'Size of the chunk header (in bytes)
	size			As Long		'Total size of this chunk (in bytes)
End Type

Private Type ResTable_header
	ResChunkHeader As ResChunk_header
	packageCount	As Long		'The number of ResTable_package structures
End Type

Private Type ResStringPool_header
	ResChunkHeader As ResChunk_header
	stringCount		As Long		'Number of strings in this pool
	styleCount		As Long		'Number of style span arrays in the pool
	flags			As Long		'flags
	stringsStart	As Long		'Index from header of the string data
	stylesStart		As Long		'Index from header of the style data
End Type

Private ResChunkHeader		As ResChunk_header
Private ResTableHeader 		As ResTable_header
Private ResStringPoolHeader	As ResStringPool_header


'获取 Android 文件及子文件的数据结构信息
Public Function GetAndroidHeaders(ByVal strFilePath As String,File As FILE_PROPERTIE,ByVal Mode As Long, _
				Optional ByVal Offset As Long = -1,Optional ByVal HeaderID As Integer = -1) As Boolean
	Dim i As Long,FN As FILE_IMAGE
	On Error GoTo ExitFunction
	File.FileSize = FileLen(strFilePath)
	'打开文件
	Mode = LoadFile(strFilePath,FN,0,0,0,Mode)
	If Mode < -1 Then Exit Function
	'获取主文件头
	GetAndroidHeaders = GetAndroidHeader(FN,File,Mode,Offset,HeaderID)
	If GetAndroidHeaders = False Then GoTo ExitFunction
	ExitFunction:
	'关闭文件
	On Error Resume Next
	UnLoadFile(FN,0,Mode)
End Function


'获取 Android 文件数据结构信息
Private Function GetAndroidHeader(FN As FILE_IMAGE,File As FILE_PROPERTIE,ByVal Mode As Long, _
				Optional ByVal Offset As Long = -1,Optional ByVal HeaderID As Integer = -1) As Boolean
	Dim i As Long
	Dim tmpResChunkHeader		As ResChunk_header
	Dim tmpResTableHeader 		As ResTable_header
	Dim tmpResStringPoolHeader	As ResStringPool_header
	ReDim File.Header(0)						'As HEADER_PROPERTIE
	ReDim File.Header(0).SecList(1)				'As SECTION_PROPERTIE
	ReDim File.Header(0).SecList(0).SubSecList(0)	'As SUB_SECTION_PROPERTIE
	ReDim File.Header(0).SecList(1).SubSecList(0)	'As SUB_SECTION_PROPERTIE
	ReDim File.Header(0).DataDirectory(0)			'As SUB_SECTION_PROPERTIE
	ReDim File.Header(0).CLRList(0)				'As SUB_SECTION_PROPERTIE
	ReDim File.Header(0).StreamList(0)			'As SUB_SECTION_PROPERTIE
	i = Offset
	If i = -1 Then i = File.FileType
	On Error GoTo ExitFunction
	File.MaxHeaderID = 0
	File.LangType = 0
	With File.Header(0)
		'初始化数据
		.Magic = ""
		.FileAlign = 0
		.SecAlign = 0
		.ImageBase = 0
		.DataDirs = 0
		.MinSecID = 0
		.MaxSecID = 0
		.MaxSecIndex = 1
		.USStreamID = -1
		.NumberOfSub = 0
		.NetStreams = 0

		Select Case GetInteger(FN,i,Mode)
		'Case RES_NULL_TYPE          	'= &H0000
		'	.Magic = "Android_RES_NULL_TYPE"
    	Case RES_STRING_POOL_TYPE        '= &H0001
    		.Magic = "Android_RES_STRING_POOL_TYPE"
    		'读取 ResStringPoolHeader 结构
			'GetTypeValue(FN,i,tmpResStringPoolHeader,Mode)
			Select Case Mode
			Case Is < 0
				Get #FN.hFile, i + 1, tmpResStringPoolHeader
			Case 0
				CopyMemory tmpResStringPoolHeader, FN.ImageByte(i), Len(tmpResStringPoolHeader)
			Case Else
				MoveMemory tmpResStringPoolHeader, FN.MappedAddress + i, Len(tmpResStringPoolHeader)
			End Select
			If tmpResStringPoolHeader.ResChunkHeader.RES_TYPE <> RES_STRING_POOL_TYPE Then GoTo ExitFunction
			If tmpResStringPoolHeader.StringCount = 0 Then GoTo ExitFunction

			'记录区段地址
			.SecList(0).sName = .Magic
			.SecList(0).lPointerToRawData = File.FileType
			.SecList(0).lSizeOfRawData = tmpResStringPoolHeader.ResChunkHeader.Size
			.SecList(0).lVirtualAddress = .SecList(0).lPointerToRawData
			.SecList(0).lVirtualSize = .SecList(0).lSizeOfRawData

			'记录 DataDirectory 地址作为字串地址和字串引用地址
			'读取 tmpResStringPoolHeader 结构
			.DataDirectory(0).lPointerToRawData = File.FileType + tmpResStringPoolHeader.stringsStart
			.DataDirectory(0).lSizeOfRawData = tmpResStringPoolHeader.ResChunkHeader.Size - tmpResStringPoolHeader.stringsStart
			.DataDirectory(0).lVirtualAddress = File.FileType + Len(tmpResStringPoolHeader)
			.DataDirectory(0).lVirtualSize = tmpResStringPoolHeader.stringsStart - Len(tmpResStringPoolHeader)
    	Case RES_TABLE_TYPE              '= &H0002
    		.Magic = "Android_RES_TABLE_TYPE"
    		'获取 tmpResTableHeader 结构
			'GetTypeValue(FN,i,tmpResTableHeader,Mode)
			Select Case Mode
			Case Is < 0
				Get #FN.hFile, i + 1, tmpResTableHeader
			Case 0
				CopyMemory tmpResTableHeader, FN.ImageByte(i), Len(tmpResTableHeader)
			Case Else
				MoveMemory tmpResTableHeader, FN.MappedAddress + i, Len(tmpResTableHeader)
			End Select
			If tmpResTableHeader.packageCount = 0 Then GoTo ExitFunction

			'读取 ResStringPoolHeader 结构
			i = i + Len(tmpResTableHeader)
			'GetTypeValue(FN,i,tmpResStringPoolHeader,Mode)
			Select Case Mode
			Case Is < 0
				Get #FN.hFile, i + 1, tmpResStringPoolHeader
			Case 0
				CopyMemory tmpResStringPoolHeader, FN.ImageByte(i), Len(tmpResStringPoolHeader)
			Case Else
				MoveMemory tmpResStringPoolHeader, FN.MappedAddress + i, Len(tmpResStringPoolHeader)
			End Select
			If tmpResStringPoolHeader.ResChunkHeader.RES_TYPE <> RES_STRING_POOL_TYPE Then GoTo ExitFunction
			If tmpResStringPoolHeader.StringCount = 0 Then GoTo ExitFunction

			'记录区段地址
			.SecList(0).sName = .Magic
			.SecList(0).lPointerToRawData = File.FileType
			.SecList(0).lSizeOfRawData = tmpResTableHeader.ResChunkHeader.Size
			.SecList(0).lVirtualAddress = .SecList(0).lPointerToRawData
			.SecList(0).lVirtualSize = .SecList(0).lSizeOfRawData

			'记录 DataDirectory 地址作为字串地址和字串引用地址
			'读取 tmpResStringPoolHeader 结构
			.DataDirectory(0).lPointerToRawData = File.FileType + Len(tmpResTableHeader) + tmpResStringPoolHeader.stringsStart
			.DataDirectory(0).lSizeOfRawData = tmpResStringPoolHeader.ResChunkHeader.Size - tmpResStringPoolHeader.stringsStart
			.DataDirectory(0).lVirtualAddress = File.FileType + Len(tmpResTableHeader) + Len(tmpResStringPoolHeader)
			.DataDirectory(0).lVirtualSize = tmpResStringPoolHeader.stringsStart - Len(tmpResStringPoolHeader)
    	Case RES_XML_TYPE                '= &H0003
    		.Magic = "Android_RES_XML_TYPE"
    		'获取 tmpResChunkHeader 结构
			'GetTypeValue(FN,i,tmpResChunkHeader,Mode)
			Select Case Mode
			Case Is < 0
				Get #FN.hFile, i + 1, tmpResChunkHeader
			Case 0
				CopyMemory tmpResChunkHeader, FN.ImageByte(i), Len(tmpResChunkHeader)
			Case Else
				MoveMemory tmpResChunkHeader, FN.MappedAddress + i, Len(tmpResChunkHeader)
			End Select

			'读取 ResStringPoolHeader 结构
			i = i + Len(tmpResChunkHeader)
			'GetTypeValue(FN,i,tmpResStringPoolHeader,Mode)
			Select Case Mode
			Case Is < 0
				Get #FN.hFile, i + 1, tmpResStringPoolHeader
			Case 0
				CopyMemory tmpResStringPoolHeader, FN.ImageByte(i), Len(tmpResStringPoolHeader)
			Case Else
				MoveMemory tmpResStringPoolHeader, FN.MappedAddress + i, Len(tmpResStringPoolHeader)
			End Select
			If tmpResStringPoolHeader.ResChunkHeader.RES_TYPE <> RES_STRING_POOL_TYPE Then GoTo ExitFunction
			If tmpResStringPoolHeader.StringCount = 0 Then GoTo ExitFunction

			'记录区段地址
			.SecList(0).sName = .Magic
			.SecList(0).lPointerToRawData = File.FileType
			.SecList(0).lSizeOfRawData = tmpResChunkHeader.Size
			.SecList(0).lVirtualAddress = .SecList(0).lPointerToRawData
			.SecList(0).lVirtualSize = .SecList(0).lSizeOfRawData

			'记录有字串区域的开始地址和大小
			.DataDirectory(0).lPointerToRawData = File.FileType + Len(tmpResChunkHeader) + tmpResStringPoolHeader.stringsStart
			.DataDirectory(0).lSizeOfRawData = tmpResStringPoolHeader.ResChunkHeader.Size - tmpResStringPoolHeader.stringsStart
			'记录有引用区域的开始地址和大小
			.DataDirectory(0).lVirtualAddress = File.FileType + Len(tmpResChunkHeader) + Len(tmpResStringPoolHeader)
			.DataDirectory(0).lVirtualSize = tmpResStringPoolHeader.stringsStart - Len(tmpResStringPoolHeader)
    	'Chunk types In RES_XML_TYPE
    	'Case RES_XML_FIRST_CHUNK_TYPE    '= &H0100
    	'	.Magic = "Android_RES_XML_FIRST_CHUNK_TYPE"
    	'Case RES_XML_START_NAMESPACE_TYPE'= &H0100
    	'	.Magic = "Android_RES_XML_START_NAMESPACE_TYPE"
    	'Case RES_XML_END_NAMESPACE_TYPE  '= &H0101
    	'	.Magic = "Android_RES_XML_END_NAMESPACE_TYPE"
    	'Case RES_XML_START_ELEMENT_TYPE  '= &H0102
    	'	.Magic = "Android_RES_XML_START_ELEMENT_TYPE"
    	'Case RES_XML_END_ELEMENT_TYPE    '= &H0103
    	'	.Magic = "Android_RES_XML_END_ELEMENT_TYPE"
    	'Case RES_XML_CDATA_TYPE          '= &H0104
    	'	.Magic = "Android_RES_XML_CDATA_TYPE"
    	'Case RES_XML_LAST_CHUNK_TYPE     '= &H017F
    	'	.Magic = "Android_RES_XML_LAST_CHUNK_TYPE"
    	'This contains a uint32_t Array mapping strings In the String
    	'pool back To resource identifiers.  It Is Optional.
    	'Case RES_XML_RESOURCE_MAP_TYPE   '= &H0180
    	'	.Magic = "Android_RES_XML_RESOURCE_MAP_TYPE"
    	'Chunk types In RES_TABLE_TYPE
    	'Case RES_TABLE_PACKAGE_TYPE      '= &H0200
    	'	.Magic = "Android_RES_TABLE_PACKAGE_TYPE"
    	'Case RES_TABLE_TYPE_TYPE         '= &H0201
    	'	.Magic = "Android_RES_TABLE_TYPE_TYPE"
    	'Case RES_TABLE_TYPE_SPEC_TYPE    '= &H0202
    	'	.Magic = "Android_ RES_TABLE_TYPE_SPEC_TYPE"
    	'Case RES_TABLE_LIBRARY_TYPE      '= &H0203
    	'	.Magic = "Android_RES_TABLE_LIBRARY_TYPE"
    	Case Else
    		GoTo ExitFunction
		End Select

		'获取引用算法中的基地址
		.ImageBase = -.DataDirectory(0).lPointerToRawData

		'获取隐藏节信息
		.SecList(.MaxSecIndex).lPointerToRawData = .SecList(.MaxSecID).lPointerToRawData + .SecList(.MaxSecID).lSizeOfRawData
		.SecList(.MaxSecIndex).lSizeOfRawData = GetFileLength(FN,Mode) - .SecList(.MaxSecIndex).lPointerToRawData
		.SecList(.MaxSecIndex).lVirtualAddress = .SecList(.MaxSecID).lVirtualAddress + .SecList(.MaxSecID).lVirtualSize
		.SecList(.MaxSecIndex).lVirtualSize = .SecList(.MaxSecIndex).lSizeOfRawData
	End With

	'记录主程序的各种头数据
	If HeaderID > -1 Then
		ResChunkHeader = tmpResChunkHeader
		ResTableHeader = tmpResTableHeader
		ResStringPoolHeader = tmpResStringPoolHeader
	End If

	'标记成功
	GetAndroidHeader = True
	Exit Function

	ExitFunction:
	'ReDim File.Header(0)					'As HEADER_PROPERTIE
	ReDim File.Header(0).SecList(1)			'As SECTION_PROPERTIE
	ReDim File.Header(0).DataDirectory(0)	'As SUB_SECTION_PROPERTIE
	ReDim File.Header(0).CLRList(0)			'As SUB_SECTION_PROPERTIE
	ReDim File.Header(0).StreamList(0)		'As SUB_SECTION_PROPERTIE
	File.MaxHeaderID = 0
	File.FileType = 0
	File.LangType = 0
	With File.Header(0)
		.Magic = ""
		.FileAlign = 0
		.SecAlign = 0
		.ImageBase = 0
		.DataDirs = 0
		.MinSecID = 0
		.MaxSecID = 0
		.MaxSecIndex = 1
		.USStreamID = -1
		.NumberOfSub = 0
		.NetStreams = 0
		.SecList(0).SubSecs = 0
		.SecList(1).SubSecs = 0
		'设置整个文件为一个节
		.SecList(0).lPointerToRawData = 0
		.SecList(0).lSizeOfRawData = GetFileLength(FN,Mode)
		.SecList(0).lVirtualAddress = 0
		.SecList(0).lVirtualSize = .SecList(0).lSizeOfRawData
		'设置隐藏节信息，用于显示文件信息
		.SecList(1).lPointerToRawData = .SecList(0).lSizeOfRawData
		.SecList(1).lSizeOfRawData = 0
		.SecList(1).lVirtualAddress = .0
		.SecList(1).lVirtualSize = 0
	End With
End Function


'增加文件节长度
'fType = 0 获取可增加的字节数，修改原始文件头不写入
'fType = 1 写入指定长度对齐后的字节数，不修改原始文件头仅写入
'fType = 2 写入指定长度对齐后的字节数，修改原始文件头
'fType = 3 不修改不写入，仅获取可增加值(AddSecSize(x).Length 为偏移大小，AddSecSize(x).Address 为虚拟大小)
'AddSecSize(x).Length = 0，按可增加的最大值增加，否则按 AddSecSize(x).Length 对齐值增加
Public Function AddAndroidSectionSize(trnFile As FILE_PROPERTIE,AddSecSize() As FREE_BTYE_SPACE,ByVal fType As Long,ByVal Mode As Long) As Long
	Dim i As Long,j As Integer,k As Long,x As Long,n As Long
	Dim AddRAW As Long
	Dim FN As FILE_IMAGE,TempByte() As Byte,File As FILE_PROPERTIE

	'错误处理
	On Error GoTo localError

	'获取 Android 头
	File = trnFile
	If GetAndroidHeaders(File.FilePath,File,Mode,-1,0) = False Then Exit Function

	'修改文件节的开始地址和大小
	With File.Header(0)
		For i = 0 To UBound(AddSecSize)
			j = AddSecSize(i).inSectionID
			'根据是否是最后节获取可增加字节
			If j = .MaxSecID Then
				AddRAW = AddRAW + AddSecSize(i).Length

				'计算并记录移位地址，用于字串移位计算操作
				If fType = 0 Then
					AddSecSize(i).Address = .SecList(j).lPointerToRawData + .SecList(j).lSizeOfRawData
					'AddSecSize.inSectionID = j
					AddSecSize(i).inSubSecID = 0
					AddSecSize(i).MaxAddress = AddSecSize(i).Address + AddSecSize(i).Length - 1
					AddSecSize(i).lNumber = -AddSecSize(i).Address
					AddSecSize(i).MoveType = -3	'新增节尾空位，不参与空位管理		.
				ElseIf fType = 1 Or fType = 2 Then
					'计算原文件当前节的偏移地址和大小，用于后面的实际移位操作
					AddSecSize(i).Address = trnFile.Header(0).SecList(j).lPointerToRawData
					AddSecSize(i).MaxAddress = AddSecSize(i).Address + trnFile.Header(0).SecList(j).lSizeOfRawData - 1
				End If

				'修改当前节的偏移大小及后面节的偏移地址
				If AddSecSize(i).Length > 0 Then
					For k = 0 To .MaxSecIndex - 1
						If .SecList(k).lPointerToRawData > .SecList(j).lPointerToRawData Then
							.SecList(k).lPointerToRawData = .SecList(k).lPointerToRawData + AddSecSize(i).Length
							.SecList(k).lVirtualAddress = .SecList(k).lVirtualAddress + AddSecSize(i).Length
						End If
					Next k
					.SecList(j).lSizeOfRawData = .SecList(j).lSizeOfRawData + AddSecSize(i).Length
					.SecList(j).lVirtualSize = .SecList(j).lVirtualSize + AddSecSize(i).Length
				End If
			Else
				AddSecSize(i).Length = 0
			End If
		Next i
		If AddRAW = 0 Then Exit Function
		If fType > 2 Then
			AddAndroidSectionSize = AddRAW
			Exit Function
		End If

		'修改隐藏节的偏移地址，还原隐藏节大小
		'由于重新读取的文件可能已在文件尾部写入了字串，这些字节将作为隐藏节被读取，故需要使用原始文件的隐藏节信息
		.SecList(.MaxSecIndex).lPointerToRawData = .SecList(.MaxSecID).lPointerToRawData + .SecList(.MaxSecID).lSizeOfRawData
		.SecList(.MaxSecIndex).lVirtualAddress = .SecList(.MaxSecID).lVirtualAddress + .SecList(.MaxSecID).lVirtualSize
		.SecList(.MaxSecIndex).lSizeOfRawData = trnFile.Header(0).SecList(trnFile.Header(0).MaxSecIndex).lSizeOfRawData
		.SecList(.MaxSecIndex).lVirtualSize = trnFile.Header(0).SecList(trnFile.Header(0).MaxSecIndex).lVirtualSize

		'修改目标文件的区段数据
		If fType = 0 Then
			trnFile = File
			AddAndroidSectionSize = AddRAW
			Exit Function
		End If
	End With

	'打开文件
	Mode = LoadFile(File.FilePath,FN,0,1,0,Mode)
	If Mode < -1 Then GoTo localError

	'修改 OptionalHeader 数据并写入
	Select Case File.Header(0).Magic
	Case "Android_RES_STRING_POOL_TYPE"        '= &H0001
		'修改字串池大小
		With ResStringPoolHeader.ResChunkHeader
			.Size = .Size + AddRAW
			'If PutTypeValue(FN,File.FileType,ResStringPoolHeader,Mode) = False Then GoTo localError
			Select Case Mode
			Case Is < 0
				Put #FN.hFile,File.FileType + 1,ResStringPoolHeader
			Case 0
				CopyMemory FN.ImageByte(File.FileType),ResStringPoolHeader,Len(ResStringPoolHeader)
			Case Else
				WriteMemory FN.MappedAddress + File.FileType,ResStringPoolHeader,Len(ResStringPoolHeader)
			End Select
		End With
	Case "Android_RES_TABLE_TYPE"              '= &H0002
		'修改文件大小
		With ResTableHeader.ResChunkHeader
			.Size = .Size + AddRAW
			'If PutTypeValue(FN,File.FileType,ResTableHeader,Mode) = False Then GoTo localError
			Select Case Mode
			Case Is < 0
				Put #FN.hFile,File.FileType + 1,ResTableHeader
			Case 0
				CopyMemory FN.ImageByte(File.FileType),ResTableHeader,Len(ResTableHeader)
			Case Else
				WriteMemory FN.MappedAddress + File.FileType,ResTableHeader,Len(ResTableHeader)
			End Select
		End With

		'修改字串池大小
		With ResStringPoolHeader.ResChunkHeader
			.Size = .Size + AddRAW
			'If PutTypeValue(FN,File.FileType + Len(ResTableHeader),ResStringPoolHeader,Mode) = False Then GoTo localError
			Select Case Mode
			Case Is < 0
				Put #FN.hFile,File.FileType + Len(ResTableHeader) + 1,ResStringPoolHeader
			Case 0
				CopyMemory FN.ImageByte(File.FileType + Len(ResTableHeader)),ResStringPoolHeader,Len(ResStringPoolHeader)
			Case Else
				WriteMemory FN.MappedAddress + File.FileType + Len(ResTableHeader),ResStringPoolHeader,Len(ResStringPoolHeader)
			End Select
		End With
    Case "Android_RES_XML_TYPE"                '= &H0003
    	'修改文件大小
		With ResChunkHeader
			.Size = .Size + AddRAW
			'If PutTypeValue(FN,File.FileType,ResChunkHeader,Mode) = False Then GoTo localError
			Select Case Mode
			Case Is < 0
				Put #FN.hFile,File.FileType + 1,ResChunkHeader
			Case 0
				CopyMemory FN.ImageByte(File.FileType),ResChunkHeader,Len(ResChunkHeader)
			Case Else
				WriteMemory FN.MappedAddress + File.FileType,ResChunkHeader,Len(ResChunkHeader)
			End Select
		End With

		'修改字串池大小
		With ResStringPoolHeader.ResChunkHeader
			.Size = .Size + AddRAW
			'If PutTypeValue(FN,File.FileType + Len(ResChunkHeader),ResStringPoolHeader,Mode) = False Then GoTo localError
			Select Case Mode
			Case Is < 0
				Put #FN.hFile,File.FileType + Len(ResChunkHeader) + 1,ResStringPoolHeader
			Case 0
				CopyMemory FN.ImageByte(File.FileType + Len(ResChunkHeader)),ResStringPoolHeader,Len(ResStringPoolHeader)
			Case Else
				WriteMemory FN.MappedAddress + File.FileType + Len(ResChunkHeader),ResStringPoolHeader,Len(ResStringPoolHeader)
			End Select
		End With
	End Select

	'从小到大对偏移地址进行排序，以避免因原节表乱序而扩展错误
	Call SortFreeByteByAddress(AddSecSize,0,UBound(AddSecSize),False)

	'移位最初要增加大小所在节后面每个节，并在节尾增加可要增加的空字节
	n = UBound(AddSecSize)
	For i = n To 0 Step -1
		With AddSecSize(i)
			j = AddSecSize(i).inSectionID
			'获取当前节后的全部字节长度
			If i = n Then
				If j = File.Header(0).MaxSecID Then
					'由于获取文件头时会重新获取文件大小，而扩展最后节时会在扩展前先写入字串，
					'故要使用原来的文件大小，否则这些写入字串会被复制到最后
					k = trnFile.FileSize - .MaxAddress - 1
				Else
					k = File.FileSize - .MaxAddress - 1
				End If
			Else
				k = AddSecSize(i + 1).MaxAddress - .MaxAddress + .Length
			End If
			'移位字节到当前节的最大地址后面
			If k > 0 Then
				TempByte = GetBytes(FN,k,.MaxAddress + 1,Mode)
				PutBytes(FN,File.Header(0).SecList(j).lPointerToRawData + File.Header(0).SecList(j).lSizeOfRawData,TempByte,k,Mode)
			End If

			'增加当前节后的空字节(置空)
			'由于重新读取的文件可能已在文件尾部写入了字串，这些字节将作为隐藏节被读取，故需要使用原始文件的隐藏节信息
			If .Length > 0 Then
				'必须使用虚拟大小，因为其大小为最大节后的所有字节(包括子 PE)
				If j = File.Header(0).MaxSecID And trnFile.Header(0).SecList(trnFile.Header(0).MaxSecIndex).lVirtualSize < 1 Then
					x = GetFileLength(FN,Mode)
					k = trnFile.FileSize + .Length - x
					If k > 0 Then
						ReDim TempByte(k - 1) As Byte
						PutBytes(FN,x,TempByte,k,Mode)
					End If
				Else
					ReDim TempByte(.Length - 1) As Byte
					PutBytes(FN,.MaxAddress + 1,TempByte,.Length,Mode)
				End If
			End If
		End With
	Next i
	UnLoadFile(FN,FN.SizeOfFile,Mode)
	AddAndroidSectionSize = AddRAW

	'修改目标文件的区段数据
	If fType = 2 Then trnFile = File
	Exit Function

	'安全退出函数
	localError:
	UnLoadFile(FN,0,Mode)
	AddAndroidSectionSize = -1
End Function
