// read utf32 and return unvalidated utf8 string get_possible_utf32(const sbuf_t &sbuf, size_t count, sbuf_t::byte_order_t byte_order) { // check for sequence if (chars_match(sbuf, count) || char_pairs_match(sbuf, count)) { // this is an uninteresting sequence, so return "" return ""; } std::string utf8_string; std::back_insert_iterator<std::basic_string<char> > result = back_inserter(utf8_string); for (uint32_t i=0; i<count; i++) { try { uint32_t code_point; code_point = sbuf.get32u(i * 4, byte_order); try { result = utf8::append(code_point, result); } catch (utf8::invalid_code_point) { // invalid code point so put in the byte values directly, // disregarding endian convention utf8_string += (uint8_t)code_point; utf8_string += (uint8_t)code_point/0x100; utf8_string += (uint8_t)code_point/0x10000; utf8_string += (uint8_t)code_point/0x1000000; } } catch (sbuf_t::range_exception_t &e) { // at end of buffer break; } } return utf8_string; }
prefetch_record_t(const sbuf_t &sbuf):prefetch_version(), header_size(0), execution_filename(), execution_counter(0), execution_time(0), volume_path_name(), volume_serial_number(0), volume_creation_time(0), files(), directories() { // read fields in order until done or range exception try { // get prefetch version identifier uint8_t prefetch_version_byte = sbuf.get8u(0); // set values based on prefetch version size_t execution_time_offset=0; size_t execution_counter_offset=0; if (prefetch_version_byte == 0x11) { prefetch_version = "Windows XP"; execution_time_offset = 0x78; execution_counter_offset = 0x90; } else if (prefetch_version_byte == 0x17) { prefetch_version = "Windows Vista or Windows 7"; execution_time_offset = 0x80; execution_counter_offset = 0x98; } else { // program error: don't create prefetch_record if this byte is invalid. // This was an assert(0), but let's just return return ; } // size in bytes of the whole prefetch file uint32_t prefetch_file_length = sbuf.get32u(0x0c); // get execution file filename wstring utf16_execution_filename; sbuf.getUTF16(0x10, utf16_execution_filename); execution_filename = safe_utf16to8(utf16_execution_filename); // get the offset to Section A uint32_t section_a_offset = sbuf.get32u(0x54); header_size = section_a_offset; // header is everything before section A // validate the offset since we know what it should be if ((prefetch_version_byte == 0x11 && header_size != 0x98) // XP and 2003 || (prefetch_version_byte == 0x17 && header_size != 0xf0)) { // Vista and 7 // invalid so quit trying return; } execution_time = sbuf.get64u(execution_time_offset); execution_counter = sbuf.get32u(execution_counter_offset); // get the list of files from Section C uint32_t section_c_offset = sbuf.get32u(0x64); uint32_t section_c_length = sbuf.get32u(0x68); sbuf_stream filename_stream(sbuf + section_c_offset); while (filename_stream.tell() < section_c_length) { wstring utf16_filename; filename_stream.getUTF16(utf16_filename); string filename = safe_utf16to8(utf16_filename); if (!valid_full_path_name(filename)) return; files.push_back(filename); } // Process Section D uint32_t section_d_offset = sbuf.get32u(0x6c); uint32_t volume_name_offset = sbuf.get32u(section_d_offset + 0x00); wstring utf16_volume_name; sbuf.getUTF16(section_d_offset+volume_name_offset, utf16_volume_name); volume_path_name = safe_utf16to8(utf16_volume_name); volume_creation_time = sbuf.get64i(section_d_offset+0x08); volume_serial_number = sbuf.get32u(section_d_offset+0x10); uint32_t section_d_2_offset = sbuf.get32u(section_d_offset + 0x1c); size_t directory_offset = section_d_offset + section_d_2_offset; uint32_t num_directory_entries = sbuf.get32u(section_d_offset + 0x20); // get each of the directory entries from Section D subsection 2 if (directory_offset > prefetch_file_length) { // the offset is out of range so don't get the list of directories } else { // calculate a rough maximum number of bytes for directory entries size_t upper_max = prefetch_file_length - directory_offset; sbuf_stream directory_stream = sbuf_stream(sbuf + directory_offset); for (uint32_t i=0; i<num_directory_entries; i++) { // break if obviously out of range if (directory_stream.tell() > upper_max) { return; // rest of data not good } // for directories, the first int16 is the directory name length. // We read to \U0000 instead so we throw away the directory name length. directory_stream.get16u(); // read the directory name wstring utf16_directory_name; directory_stream.getUTF16(utf16_directory_name); string directory_name = safe_utf16to8(utf16_directory_name); if (!valid_full_path_name(directory_name)) return; directories.push_back(directory_name); } } } catch (sbuf_t::range_exception_t &e) { // no action, just return what was gleaned before range exception } }