This commit is contained in:
Joao Moreno 2018-01-01 22:45:52 +00:00
Родитель 0345b56043
Коммит 5548486a44
4 изменённых файлов: 222 добавлений и 204 удалений

0
src/filerec.rs Normal file
Просмотреть файл

Просмотреть файл

@ -2,219 +2,25 @@ extern crate byteorder;
extern crate crc;
mod blockio;
mod strings;
mod model;
use std::io;
use std::io::prelude::*;
use std::fmt;
use std::fs;
use std::vec::Vec;
use std::string;
use std::collections::HashMap;
use byteorder::{LittleEndian, ReadBytesExt};
use crc::{crc32, Hasher32};
#[derive(Debug)]
enum ReadUtf8StringError {
IOError(io::Error),
UTF8Error(string::FromUtf8Error),
}
fn read_utf8_string(reader: &mut Read, capacity: usize) -> Result<String, ReadUtf8StringError> {
let mut vec = vec![0; capacity];
reader
.read_exact(&mut vec)
.map_err(|err| ReadUtf8StringError::IOError(err))
.and_then(|_| {
let pos = vec.iter().position(|&x| x == 0).unwrap_or(64);
let bar = &vec[0..pos];
String::from_utf8(Vec::from(bar)).map_err(|err| ReadUtf8StringError::UTF8Error(err))
})
}
// FILE REC
#[derive(Copy, Clone)]
enum UninstallRecTyp {
UserDefined = 0x01,
StartInstall = 0x10,
EndInstall = 0x11,
CompiledCode = 0x20,
Run = 0x80,
DeleteDirOrFiles = 0x81,
DeleteFile = 0x82,
DeleteGroupOrItem = 0x83,
IniDeleteEntry = 0x84,
IniDeleteSection = 0x85,
RegDeleteEntireKey = 0x86,
RegClearValue = 0x87,
RegDeleteKeyIfEmpty = 0x88,
RegDeleteValue = 0x89,
DecrementSharedCount = 0x8A,
RefreshFileAssoc = 0x8B,
MutexCheck = 0x8C,
}
impl UninstallRecTyp {
fn from(i: u16) -> UninstallRecTyp {
match i {
0x01 => UninstallRecTyp::UserDefined,
0x10 => UninstallRecTyp::StartInstall,
0x11 => UninstallRecTyp::EndInstall,
0x20 => UninstallRecTyp::CompiledCode,
0x80 => UninstallRecTyp::Run,
0x81 => UninstallRecTyp::DeleteDirOrFiles,
0x82 => UninstallRecTyp::DeleteFile,
0x83 => UninstallRecTyp::DeleteGroupOrItem,
0x84 => UninstallRecTyp::IniDeleteEntry,
0x85 => UninstallRecTyp::IniDeleteSection,
0x86 => UninstallRecTyp::RegDeleteEntireKey,
0x87 => UninstallRecTyp::RegClearValue,
0x88 => UninstallRecTyp::RegDeleteKeyIfEmpty,
0x89 => UninstallRecTyp::RegDeleteValue,
0x8A => UninstallRecTyp::DecrementSharedCount,
0x8B => UninstallRecTyp::RefreshFileAssoc,
0x8C => UninstallRecTyp::MutexCheck,
_ => panic!(""),
}
}
}
struct FileRec {
typ: UninstallRecTyp,
extra_data: u32,
data: Vec<u8>,
}
impl<'a> std::fmt::Debug for FileRec {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter,
"FileRec 0x{:x} 0x{:x} {} bytes",
self.typ as u32,
self.extra_data as u32,
self.data.len(),
)
}
}
impl<'a> FileRec {
fn from_reader(reader: &mut Read) -> FileRec {
let typ = reader.read_u16::<LittleEndian>().expect("file rec typ");
let extra_data = reader.read_u32::<LittleEndian>().expect("file rec extra data");
let data_size = reader.read_u32::<LittleEndian>().expect("file rec data size") as usize;
if data_size > 0x8000000 {
panic!("file rec data size too large {}", data_size);
}
let mut data = vec![0; data_size];
reader.read_exact(&mut data).expect("file rec data");
let typ = UninstallRecTyp::from(typ);
FileRec {
typ,
extra_data,
data,
}
}
}
// HEADER
const HEADER_SIZE: usize = 448;
const HEADER_ID_32: &str = "Inno Setup Uninstall Log (b)";
const HEADER_ID_64: &str = "Inno Setup Uninstall Log (b) 64-bit";
const HIGHEST_SUPPORTED_VERSION: i32 = 1048;
struct Header {
id: String, // 64 bytes
app_id: String, // 128
app_name: String, // 128
version: i32,
num_recs: usize,
end_offset: u32,
flags: u32,
crc: u32,
}
impl std::fmt::Debug for Header {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter,
"Header\nid: {}\napp id: {}\napp name: {}\nversion: {}\nnum recs: {}\nend offset: {}\nflags: 0x{:x}\ncrc: 0x{:x}",
self.id,
self.app_id,
self.app_name,
self.version,
self.num_recs,
self.end_offset,
self.flags,
self.crc,
)
}
}
impl Header {
fn from_reader(reader: &mut Read) -> Header {
let mut buf = [0; HEADER_SIZE];
reader.read_exact(&mut buf).expect("read error");
let mut read: &[u8] = &buf;
let id = read_utf8_string(&mut read, 64).expect("header id");
let app_id = read_utf8_string(&mut read, 128).expect("header app id");
let app_name = read_utf8_string(&mut read, 128).expect("header app name");
let version = read.read_i32::<LittleEndian>().expect("header version");
let num_recs = read.read_i32::<LittleEndian>().expect("header num recs") as usize;
let end_offset = read
.read_u32::<LittleEndian>()
.expect("header end offset");
let flags = read.read_u32::<LittleEndian>().expect("header flags");
let mut reserved = [0; 108];
read.read_exact(&mut reserved).expect("header reserved");
let crc = read.read_u32::<LittleEndian>().expect("header crc");
let mut digest = crc32::Digest::new(crc32::IEEE);
digest.write(&buf[..HEADER_SIZE-4]);
let actual_crc = digest.sum32();
if actual_crc != crc {
panic!("header crc32 check failed");
}
match id.as_ref() {
HEADER_ID_32 => (),
HEADER_ID_64 => (),
_ => panic!("header id not valid")
}
if version > HIGHEST_SUPPORTED_VERSION {
panic!("header version not supported");
}
Header {
id,
app_id,
app_name,
version,
num_recs,
end_offset,
flags,
crc,
}
}
}
// MAIN
fn print_statistics(recs: &[FileRec]) {
let mut map: HashMap<u16,u32> = HashMap::new();
fn print_statistics(recs: &[model::FileRec]) {
let mut map: HashMap<u16, u32> = HashMap::new();
for rec in recs {
let count = map.entry(rec.typ as u16).or_insert(0);
*count += 1;
*count += 1;
}
println!("Statistics");
for (k, c) in &map {
println!("records 0x{:x} {}", k, c);
}
@ -224,14 +30,14 @@ fn main() {
let filename = "unins000.dat";
let mut f = fs::File::open(filename).expect("file not found");
let header = Header::from_reader(&mut f);
let header = model::Header::from_reader(&mut f);
let mut reader = blockio::BlockRead::new(&mut f);
let mut recs = Vec::with_capacity(header.num_recs);
for _ in 0..header.num_recs {
recs.push(FileRec::from_reader(&mut reader));
recs.push(model::FileRec::from_reader(&mut reader));
}
// println!("{:?}", header);
println!("{:?}", header);
print_statistics(&recs);
}

190
src/model.rs Normal file
Просмотреть файл

@ -0,0 +1,190 @@
use std::fmt;
use strings;
use std::io::prelude::*;
use byteorder::{LittleEndian, ReadBytesExt};
use crc::{Hasher32, crc32};
// HEADER
const HEADER_SIZE: usize = 448;
const HEADER_ID_32: &str = "Inno Setup Uninstall Log (b)";
const HEADER_ID_64: &str = "Inno Setup Uninstall Log (b) 64-bit";
const HIGHEST_SUPPORTED_VERSION: i32 = 1048;
pub struct Header {
id: String, // 64 bytes
app_id: String, // 128
app_name: String, // 128
version: i32,
pub num_recs: usize,
end_offset: u32,
flags: u32,
crc: u32,
}
impl fmt::Debug for Header {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(
formatter,
"Header
id: {}
app id: {}
app name: {}
version: {}
num recs: {}
end offset: {}
flags: 0x{:x}
crc: 0x{:x}",
self.id,
self.app_id,
self.app_name,
self.version,
self.num_recs,
self.end_offset,
self.flags,
self.crc,
)
}
}
impl Header {
pub fn from_reader(reader: &mut Read) -> Header {
let mut buf = [0; HEADER_SIZE];
reader.read_exact(&mut buf).expect("read error");
let mut read: &[u8] = &buf;
let id = strings::read_utf8_string(&mut read, 64).expect("header id");
let app_id = strings::read_utf8_string(&mut read, 128).expect("header app id");
let app_name = strings::read_utf8_string(&mut read, 128).expect("header app name");
let version = read.read_i32::<LittleEndian>().expect("header version");
let num_recs = read.read_i32::<LittleEndian>().expect("header num recs") as usize;
let end_offset = read.read_u32::<LittleEndian>().expect("header end offset");
let flags = read.read_u32::<LittleEndian>().expect("header flags");
let mut reserved = [0; 108];
read.read_exact(&mut reserved).expect("header reserved");
let crc = read.read_u32::<LittleEndian>().expect("header crc");
let mut digest = crc32::Digest::new(crc32::IEEE);
digest.write(&buf[..HEADER_SIZE - 4]);
let actual_crc = digest.sum32();
if actual_crc != crc {
panic!("header crc32 check failed");
}
match id.as_ref() {
HEADER_ID_32 => (),
HEADER_ID_64 => (),
_ => panic!("header id not valid"),
}
if version > HIGHEST_SUPPORTED_VERSION {
panic!("header version not supported");
}
Header {
id,
app_id,
app_name,
version,
num_recs,
end_offset,
flags,
crc,
}
}
}
// FILE REC
#[derive(Copy, Clone)]
pub enum UninstallRecTyp {
UserDefined = 0x01,
StartInstall = 0x10,
EndInstall = 0x11,
CompiledCode = 0x20,
Run = 0x80,
DeleteDirOrFiles = 0x81,
DeleteFile = 0x82,
DeleteGroupOrItem = 0x83,
IniDeleteEntry = 0x84,
IniDeleteSection = 0x85,
RegDeleteEntireKey = 0x86,
RegClearValue = 0x87,
RegDeleteKeyIfEmpty = 0x88,
RegDeleteValue = 0x89,
DecrementSharedCount = 0x8A,
RefreshFileAssoc = 0x8B,
MutexCheck = 0x8C,
}
impl UninstallRecTyp {
fn from(i: u16) -> UninstallRecTyp {
match i {
0x01 => UninstallRecTyp::UserDefined,
0x10 => UninstallRecTyp::StartInstall,
0x11 => UninstallRecTyp::EndInstall,
0x20 => UninstallRecTyp::CompiledCode,
0x80 => UninstallRecTyp::Run,
0x81 => UninstallRecTyp::DeleteDirOrFiles,
0x82 => UninstallRecTyp::DeleteFile,
0x83 => UninstallRecTyp::DeleteGroupOrItem,
0x84 => UninstallRecTyp::IniDeleteEntry,
0x85 => UninstallRecTyp::IniDeleteSection,
0x86 => UninstallRecTyp::RegDeleteEntireKey,
0x87 => UninstallRecTyp::RegClearValue,
0x88 => UninstallRecTyp::RegDeleteKeyIfEmpty,
0x89 => UninstallRecTyp::RegDeleteValue,
0x8A => UninstallRecTyp::DecrementSharedCount,
0x8B => UninstallRecTyp::RefreshFileAssoc,
0x8C => UninstallRecTyp::MutexCheck,
_ => panic!(""),
}
}
}
pub struct FileRec {
pub typ: UninstallRecTyp,
extra_data: u32,
data: Vec<u8>,
}
impl<'a> fmt::Debug for FileRec {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(
formatter,
"FileRec 0x{:x} 0x{:x} {} bytes",
self.typ as u32,
self.extra_data as u32,
self.data.len(),
)
}
}
impl<'a> FileRec {
pub fn from_reader(reader: &mut Read) -> FileRec {
let typ = reader.read_u16::<LittleEndian>().expect("file rec typ");
let extra_data = reader
.read_u32::<LittleEndian>()
.expect("file rec extra data");
let data_size = reader
.read_u32::<LittleEndian>()
.expect("file rec data size") as usize;
if data_size > 0x8000000 {
panic!("file rec data size too large {}", data_size);
}
let mut data = vec![0; data_size];
reader.read_exact(&mut data).expect("file rec data");
let typ = UninstallRecTyp::from(typ);
FileRec {
typ,
extra_data,
data,
}
}
}

22
src/strings.rs Normal file
Просмотреть файл

@ -0,0 +1,22 @@
use std::io;
use std::string;
use std::io::prelude::*;
#[derive(Debug)]
pub enum ReadUtf8StringError {
IOError(io::Error),
UTF8Error(string::FromUtf8Error),
}
pub fn read_utf8_string(reader: &mut Read, capacity: usize) -> Result<String, ReadUtf8StringError> {
let mut vec = vec![0; capacity];
reader
.read_exact(&mut vec)
.map_err(|err| ReadUtf8StringError::IOError(err))
.and_then(|_| {
let pos = vec.iter().position(|&x| x == 0).unwrap_or(64);
let bar = &vec[0..pos];
String::from_utf8(Vec::from(bar)).map_err(|err| ReadUtf8StringError::UTF8Error(err))
})
}