Skip to content

Instantly share code, notes, and snippets.

@kusabanachi
Last active August 29, 2015 14:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kusabanachi/1964639d2e7981a182b4 to your computer and use it in GitHub Desktop.
Save kusabanachi/1964639d2e7981a182b4 to your computer and use it in GitHub Desktop.
.textセクションのみのEXEファイルを作成
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