Last active
August 29, 2015 14:03
-
-
Save kusabanachi/1964639d2e7981a182b4 to your computer and use it in GitHub Desktop.
.textセクションのみのEXEファイルを作成
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open System | |
open System.IO | |
// 2byteの配列をWord値に変換 | |
let ToWord byteArray = | |
BitConverter.ToUInt16(byteArray, 0) | |
// 4byteの配列をDWord値に変換 | |
let ToDWord byteArray = | |
BitConverter.ToUInt32(byteArray, 0) | |
// Word値を2Byteの配列に変換 | |
let WordsToBytes wordArray = | |
let arrayOfByteArray = Array.map (BitConverter.GetBytes: uint16 -> byte []) wordArray | |
Array.concat arrayOfByteArray | |
// 先頭のヘッダ部 | |
type ImageDosHeader = { | |
magic : uint16 | |
cblp : uint16 | |
cp : uint16 | |
crlc : uint16 | |
cparhdr : uint16 | |
minalloc : uint16 | |
maxalloc : uint16 | |
ss : uint16 | |
sp : uint16 | |
csum : uint16 | |
ip : uint16 | |
cs : uint16 | |
lfarlc : uint16 | |
ovno : uint16 | |
res : uint16 [] | |
oemid : uint16 | |
oeminfo : uint16 | |
res2 : uint16 [] | |
lfanew : uint32 | |
} with | |
// Byte配列 | |
member this.byteArray() = | |
Array.concat [ | |
BitConverter.GetBytes(this.magic) | |
BitConverter.GetBytes(this.cblp) | |
BitConverter.GetBytes(this.cp) | |
BitConverter.GetBytes(this.crlc) | |
BitConverter.GetBytes(this.cparhdr) | |
BitConverter.GetBytes(this.minalloc) | |
BitConverter.GetBytes(this.maxalloc) | |
BitConverter.GetBytes(this.ss) | |
BitConverter.GetBytes(this.sp) | |
BitConverter.GetBytes(this.csum) | |
BitConverter.GetBytes(this.ip) | |
BitConverter.GetBytes(this.cs) | |
BitConverter.GetBytes(this.lfarlc) | |
BitConverter.GetBytes(this.ovno) | |
WordsToBytes this.res | |
BitConverter.GetBytes(this.oemid) | |
BitConverter.GetBytes(this.oeminfo) | |
WordsToBytes this.res2 | |
BitConverter.GetBytes(this.lfanew) | |
] | |
// ヘッダ部その2 | |
type DosStub = { | |
stubCode : Byte [] | |
message : Byte [] | |
} with | |
// Byte配列 | |
member this.byteArray() = | |
Array.append this.stubCode this.message | |
// ヘッダ部その2 | |
type ImageFileHeader = { | |
machine : uint16 | |
numberOfSections : uint16 | |
timeDateStamp : uint32 | |
pointerToSymbolTable : uint32 | |
numberOfSymbols : uint32 | |
sizeOfOptionalHeader : uint16 | |
characteristics : uint16 | |
} with | |
// Byte配列 | |
member this.byteArray() = | |
Array.concat [ | |
BitConverter.GetBytes(this.machine) | |
BitConverter.GetBytes(this.numberOfSections) | |
BitConverter.GetBytes(this.timeDateStamp) | |
BitConverter.GetBytes(this.pointerToSymbolTable) | |
BitConverter.GetBytes(this.numberOfSymbols) | |
BitConverter.GetBytes(this.sizeOfOptionalHeader) | |
BitConverter.GetBytes(this.characteristics) | |
] | |
// ヘッダ部その3に含まれる | |
type ImageDataDictionary = { | |
virtualAddress : uint32 | |
size : uint32 | |
} with | |
// Byte配列 | |
member this.byteArray() = | |
Array.concat [ | |
BitConverter.GetBytes(this.virtualAddress) | |
BitConverter.GetBytes(this.size) | |
] | |
// ヘッダ部その3 | |
type ImageOptionalHeader = { | |
magic : uint16 | |
majorLinkerVersion : Byte | |
minorLinkerVersion : Byte | |
sizeOfCode : uint32 | |
sizeOfInitializedData : uint32 | |
sizeOfUninitializedData : uint32 | |
addressOfEntryPoint : uint32 | |
baseOfCode : uint32 | |
baseOfData : uint32 | |
imageBase : uint32 | |
sectionAlignment : uint32 | |
fileAlignment : uint32 | |
majorOperatingSystemVersion : uint16 | |
minorOperatingSystemVersion : uint16 | |
majorImageVersion : uint16 | |
minorImageVersion : uint16 | |
majorSubsystemVersion : uint16 | |
minorSubsystemVersion : uint16 | |
win32VersionValue : uint32 | |
sizeOfImage : uint32 | |
sizeOfHeaders : uint32 | |
checkSum : uint32 | |
subsystem : uint16 | |
dllCharacteristics : uint16 | |
sizeOfStackReserve : uint32 | |
sizeOfStackCommit : uint32 | |
sizeOfHeapReserve : uint32 | |
sizeOfHeapCommit : uint32 | |
loaderFlags : uint32 | |
numberOfRvaAndSizes : uint32 | |
dataDictionary : ImageDataDictionary [] | |
} with | |
// Byte配列 | |
member this.byteArray() = | |
Array.concat [ | |
BitConverter.GetBytes(this.magic) | |
[|this.majorLinkerVersion|] | |
[|this.minorLinkerVersion|] | |
BitConverter.GetBytes(this.sizeOfCode) | |
BitConverter.GetBytes(this.sizeOfInitializedData) | |
BitConverter.GetBytes(this.sizeOfUninitializedData) | |
BitConverter.GetBytes(this.addressOfEntryPoint) | |
BitConverter.GetBytes(this.baseOfCode) | |
BitConverter.GetBytes(this.baseOfData) | |
BitConverter.GetBytes(this.imageBase) | |
BitConverter.GetBytes(this.sectionAlignment) | |
BitConverter.GetBytes(this.fileAlignment) | |
BitConverter.GetBytes(this.majorOperatingSystemVersion) | |
BitConverter.GetBytes(this.minorOperatingSystemVersion) | |
BitConverter.GetBytes(this.majorImageVersion) | |
BitConverter.GetBytes(this.minorImageVersion) | |
BitConverter.GetBytes(this.majorSubsystemVersion) | |
BitConverter.GetBytes(this.minorSubsystemVersion) | |
BitConverter.GetBytes(this.win32VersionValue) | |
BitConverter.GetBytes(this.sizeOfImage) | |
BitConverter.GetBytes(this.sizeOfHeaders) | |
BitConverter.GetBytes(this.checkSum) | |
BitConverter.GetBytes(this.subsystem) | |
BitConverter.GetBytes(this.dllCharacteristics) | |
BitConverter.GetBytes(this.sizeOfStackReserve) | |
BitConverter.GetBytes(this.sizeOfStackCommit) | |
BitConverter.GetBytes(this.sizeOfHeapReserve) | |
BitConverter.GetBytes(this.sizeOfHeapCommit) | |
BitConverter.GetBytes(this.loaderFlags) | |
BitConverter.GetBytes(this.numberOfRvaAndSizes) | |
Array.concat( | |
Array.map (fun (d:ImageDataDictionary) -> d.byteArray()) this.dataDictionary) | |
] | |
// シグネチャとヘッダ部2と3を含む | |
type ImageNtHeaders = { | |
signature : uint32 | |
fileHeader : ImageFileHeader | |
optionalHeader : ImageOptionalHeader | |
} with | |
// Byte配列 | |
member this.byteArray() = | |
Array.concat [ | |
BitConverter.GetBytes(this.signature) | |
this.fileHeader.byteArray() | |
this.optionalHeader.byteArray() | |
] | |
// セクションごとのヘッダ | |
type ImageSectionHeader = { | |
name : Byte [] | |
virtualSize : uint32 | |
virtualAddress : uint32 | |
sizeOfRawData : uint32 | |
pointerToRawData : uint32 | |
pointerToRelocations : uint32 | |
pointerToLinenumbers : uint32 | |
numberOfRelocations : uint16 | |
numberOfLinenumbers : uint16 | |
characteristics : uint32 | |
} with | |
member this.byteArray() = | |
Array.concat [ | |
this.name | |
BitConverter.GetBytes(this.virtualSize) | |
BitConverter.GetBytes(this.virtualAddress) | |
BitConverter.GetBytes(this.sizeOfRawData) | |
BitConverter.GetBytes(this.pointerToRawData) | |
BitConverter.GetBytes(this.pointerToRelocations) | |
BitConverter.GetBytes(this.pointerToLinenumbers) | |
BitConverter.GetBytes(this.numberOfRelocations) | |
BitConverter.GetBytes(this.numberOfLinenumbers) | |
BitConverter.GetBytes(this.characteristics) | |
] | |
// テキストセクション | |
type TextSection = Byte [] | |
// i386を表す値 | |
let machine_i386 = 0x14Cus | |
// CUIを表す値 | |
let subsystem_CUI = 3us | |
// ヘッダ部2のcharacterristics値 | |
type PeCharacteristics = | |
| FileExecutable = 0x0002us | |
| File32BitMachine = 0x0100us | |
// セクションヘッダのcharacterristics値 | |
type SectionCharacteristics = | |
| Code = 0x20ul | |
| InitData = 0x40ul | |
| UninitData = 0x80ul | |
| Execute = 0x20000000ul | |
| Read = 0x40000000ul | |
| Write = 0x80000000ul | |
// 単位の倍数に切り上げ | |
let roundUp unitValue srcValue = | |
(srcValue + (unitValue - 1)) / unitValue * unitValue | |
// アライメント | |
let alignTo size (data : byte []) = | |
let padSize = (roundUp size data.Length) - data.Length | |
Array.append data (Array.create padSize 0uy) | |
// 指定サイズまで0を詰める | |
let addPaddingTo size (data : byte []) = | |
let padSize = size - data.Length | |
Array.append data (Array.create padSize 0uy) | |
// 配列の結合 | |
let cat = Array.append | |
// テキストセクションのみのExeファイル | |
type simpleTextOnlyExe(text : TextSection, entryPointOffsetInText) = | |
let peHeaderAddress = 0x80ul | |
let pe32BitExecutable = uint16 (PeCharacteristics.FileExecutable ||| PeCharacteristics.File32BitMachine) | |
let simpleSectionAlign = 0x1000ul | |
let simpleBaseOfCode = uint32 (simpleSectionAlign * 1u) | |
let simpleFileAlign = 0x200ul | |
let simpleTextSectionSize = uint32 (roundUp (int simpleSectionAlign) text.Length) | |
let simpleTextFileSize = uint32 (roundUp (int simpleFileAlign) text.Length) | |
let simpleTextFileAddress = simpleFileAlign * 1u; | |
let textSectionFlag = uint32 (SectionCharacteristics.Code ||| | |
SectionCharacteristics.Execute ||| | |
SectionCharacteristics.Read) | |
let simpleImageDosHeader = { | |
magic = "MZ"B |> ToWord | |
cblp = 0x90us; cp = 0x03us; crlc = 0x0us; | |
cparhdr = 0x4us; minalloc = 0x0us; maxalloc = 0xFFFFus | |
ss = 0x0us; sp = 0xB8us; csum = 0x0us; | |
ip = 0x0us; cs = 0x0us; lfarlc = 0x40us; | |
ovno = 0x0us; | |
res = 0us |> Array.create 4; | |
oemid = 0x0us; oeminfo = 0x0us; | |
res2 = 0us |> Array.create 10; | |
lfanew = peHeaderAddress | |
} | |
let simpleDosStub = { | |
stubCode = [|0x0Euy; 0x1Fuy; 0xBAuy; 0x0Euy; | |
0x00uy; 0xB4uy; 0x09uy; 0xCDuy; | |
0x21uy; 0xB8uy; 0x01uy; 0x4Cuy; | |
0xCDuy; 0x21uy|]; | |
message = "This program cannot be run in DOS mode.\r\r\n$"B; | |
} | |
let simpleNtHeaders = { | |
signature = "PE\000\000"B |> ToDWord; | |
fileHeader = | |
{ | |
machine = machine_i386; | |
numberOfSections = 1us; | |
timeDateStamp = 0ul; // later | |
pointerToSymbolTable = 0ul; | |
numberOfSymbols = 0ul; | |
sizeOfOptionalHeader = 0xE0us; | |
characteristics = pe32BitExecutable; | |
} | |
optionalHeader = | |
{ | |
magic = 0x010Bus; | |
majorLinkerVersion = 0x0Auy; | |
minorLinkerVersion = 0x00uy; | |
sizeOfCode = uint32 text.Length; | |
sizeOfInitializedData = 0x0ul; | |
sizeOfUninitializedData = 0x0ul; | |
addressOfEntryPoint = simpleBaseOfCode + entryPointOffsetInText; | |
baseOfCode = simpleBaseOfCode; | |
baseOfData = 0x0ul; | |
imageBase = 0x400000ul; | |
sectionAlignment = simpleSectionAlign; | |
fileAlignment = simpleFileAlign; | |
majorOperatingSystemVersion = 5us; | |
minorOperatingSystemVersion = 1us; | |
majorImageVersion = 0us; | |
minorImageVersion = 0us; | |
majorSubsystemVersion = 5us; | |
minorSubsystemVersion = 1us; | |
win32VersionValue = 0ul; | |
sizeOfImage = simpleSectionAlign + simpleTextSectionSize; | |
sizeOfHeaders = simpleFileAlign * 1u; | |
checkSum = 0ul; | |
subsystem = subsystem_CUI; | |
dllCharacteristics = 0us; | |
sizeOfStackReserve = 0x100000ul; | |
sizeOfStackCommit = 0x1000ul; | |
sizeOfHeapReserve = 0x100000ul; | |
sizeOfHeapCommit = 0x1000ul; | |
loaderFlags = 0ul; | |
numberOfRvaAndSizes = 16ul; | |
dataDictionary = { virtualAddress = 0ul; size = 0ul; } |> Array.create 16; | |
} | |
} | |
let simpleTextSectionHeader = { | |
name = ".text\000\000\000"B; | |
virtualSize = simpleTextSectionSize; | |
virtualAddress = simpleBaseOfCode; | |
sizeOfRawData = simpleTextFileSize; | |
pointerToRawData = simpleTextFileAddress | |
pointerToRelocations = 0ul; | |
pointerToLinenumbers = 0ul; | |
numberOfRelocations = 0us; | |
numberOfLinenumbers = 0us; | |
characteristics = textSectionFlag; | |
} | |
let simpleTextSection = text | |
// ファイル出力 | |
member this.write(filePath) = | |
// タイムスタンプのフィールドだけ、出力時に算出する | |
let myTimeStamp = uint32 (DateTime.UtcNow - DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalSeconds | |
// タイムスタンプだけ書き換えたヘッダ | |
let newNtHeaders = { simpleNtHeaders with | |
fileHeader = { simpleNtHeaders.fileHeader with timeDateStamp = myTimeStamp } } | |
// パディングを入れて、各ヘッダとセクションを結合 | |
let exeBytes = | |
simpleImageDosHeader.byteArray() | |
|> cat <| | |
simpleDosStub.byteArray() | |
|> addPaddingTo (int peHeaderAddress) | |
|> cat <| | |
newNtHeaders.byteArray() | |
|> cat <| | |
simpleTextSectionHeader.byteArray() | |
|> addPaddingTo (int simpleTextFileAddress) | |
|> cat <| | |
simpleTextSection | |
|> addPaddingTo (int (simpleTextFileAddress + simpleTextFileSize)) | |
// 出力 | |
File.WriteAllBytes(filePath, exeBytes) | |
() | |
[<EntryPoint>] | |
let main args = | |
// 5を返すだけのコード | |
let ret5Code = [|0xB8uy; 0x5uy; 0x0uy; 0x0uy; 0x0uy; // mov eax, 0x5 | |
0xc3uy|] // ret | |
let outFilePath = "mySimpleExe.exe" | |
let myExe = simpleTextOnlyExe(text = ret5Code, entryPointOffsetInText = 0ul) | |
myExe.write(outFilePath) | |
0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment