1
0
mirror of synced 2024-11-12 02:00:52 +01:00

feat: Added LEB128 in data inspector (#615)

* feat: Added LEB128 in data inspector

* feat: Added support for editing LEB128 values

* Moved LEB functions from utils.cpp to crypto.cpp

* Added placeholders for translations

* Made DataInspector::impl::Entry.maxSize mandatory

* Fixed undefined leftshifting behaviour
This commit is contained in:
gudzpoz 2022-08-01 19:20:20 +08:00 committed by GitHub
parent 64f962dbb2
commit eca5fb894f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 200 additions and 3 deletions

View File

@ -206,6 +206,7 @@ namespace hex {
struct Entry {
std::string unlocalizedName;
size_t requiredSize;
size_t maxSize;
impl::GeneratorFunction generatorFunction;
std::optional<impl::EditingFunction> editingFunction;
};
@ -213,6 +214,7 @@ namespace hex {
}
void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction = std::nullopt);
void add(const std::string &unlocalizedName, size_t requiredSize, size_t maxSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction = std::nullopt);
std::vector<impl::Entry> &getEntries();
}

View File

@ -39,6 +39,11 @@ namespace hex::crypt {
std::vector<u8> decode16(const std::string &input);
std::string encode16(const std::vector<u8> &input);
i128 decodeSleb128(const std::vector<u8> &bytes);
u128 decodeUleb128(const std::vector<u8> &bytes);
std::vector<u8> encodeSleb128(i128 value);
std::vector<u8> encodeUleb128(u128 value);
enum class AESMode : u8 {
ECB = 0,
CBC = 1,

View File

@ -348,7 +348,13 @@ namespace hex {
void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction) {
log::debug("Registered new data inspector format: {}", unlocalizedName);
getEntries().push_back({ unlocalizedName, requiredSize, std::move(displayGeneratorFunction), std::move(editingFunction) });
getEntries().push_back({ unlocalizedName, requiredSize, requiredSize, std::move(displayGeneratorFunction), std::move(editingFunction) });
}
void add(const std::string &unlocalizedName, size_t requiredSize, size_t maxSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction) {
log::info("Registered new data inspector format: {}", unlocalizedName);
getEntries().push_back({ unlocalizedName, requiredSize, maxSize, std::move(displayGeneratorFunction), std::move(editingFunction) });
}
std::vector<impl::Entry> &getEntries() {

View File

@ -422,6 +422,77 @@ namespace hex::crypt {
return output;
}
template<typename T>
static T safeLeftShift(T t, u32 shift) {
if (shift >= sizeof(t) * 8) {
return 0;
} else {
return t << shift;
}
}
template<typename T>
static T decodeLeb128(const std::vector<u8> &bytes) {
T value = 0;
u32 shift = 0;
u8 b = 0;
for (u8 byte : bytes) {
b = byte;
value |= safeLeftShift(static_cast<T>(byte & 0x7F), shift);
shift += 7;
if ((byte & 0x80) == 0) {
break;
}
}
if constexpr(std::is_signed<T>::value) {
if ((b & 0x40) != 0) {
value |= safeLeftShift(~static_cast<T>(0), shift);
}
}
return value;
}
u128 decodeUleb128(const std::vector<u8> &bytes) {
return decodeLeb128<u128>(bytes);
}
i128 decodeSleb128(const std::vector<u8> &bytes) {
return decodeLeb128<i128>(bytes);
}
template<typename T>
static std::vector<u8> encodeLeb128(T value) {
std::vector<u8> bytes;
u8 byte;
while (true) {
byte = value & 0x7F;
value >>= 7;
if constexpr(std::is_signed<T>::value) {
if (value == 0 && (byte & 0x40) == 0) {
break;
}
if (value == -1 && (byte & 0x40) != 0) {
break;
}
} else {
if (value == 0) {
break;
}
}
bytes.push_back(byte | 0x80);
}
bytes.push_back(byte);
return bytes;
}
std::vector<u8> encodeUleb128(u128 value) {
return encodeLeb128<u128>(value);
}
std::vector<u8> encodeSleb128(i128 value) {
return encodeLeb128<i128>(value);
}
static std::vector<u8> aes(mbedtls_cipher_type_t type, mbedtls_operation_t operation, const std::vector<u8> &key, std::array<u8, 8> nonce, std::array<u8, 8> iv, const std::vector<u8> &input) {
std::vector<u8> output;

View File

@ -2,6 +2,7 @@
#include <hex/helpers/utils.hpp>
#include <hex/helpers/fmt.hpp>
#include <hex/helpers/crypto.hpp>
#include <hex/api/event.hpp>
#include <hex/providers/provider.hpp>
@ -264,6 +265,42 @@ namespace hex::plugin::builtin {
stringToFloat<long double>
);
ContentRegistry::DataInspector::add("hex.builtin.inspector.sleb128", 1, (sizeof(i128) * 8 / 7) + 1,
[](auto buffer, auto endian, auto style) {
hex::unused(endian);
auto format = (style == Style::Decimal) ? "{0}{1:d}" : ((style == Style::Hexadecimal) ? "{0}0x{1:X}" : "{0}0o{1:o}");
auto number = hex::crypt::decodeSleb128(buffer);
bool negative = number < 0;
auto value = hex::format(format, negative ? "-" : "", std::abs(number));
return [value] { ImGui::TextUnformatted(value.c_str()); return value; };
},
[](const std::string &value, std::endian endian) -> std::vector<u8> {
hex::unused(endian);
return hex::crypt::encodeSleb128(std::strtoll(value.c_str(), nullptr, 0));
}
);
ContentRegistry::DataInspector::add("hex.builtin.inspector.uleb128", 1, (sizeof(u128) * 8 / 7) + 1,
[](auto buffer, auto endian, auto style) {
hex::unused(endian);
auto format = (style == Style::Decimal) ? "{0:d}" : ((style == Style::Hexadecimal) ? "0x{0:X}" : "0o{0:o}");
auto value = hex::format(format, hex::crypt::decodeUleb128(buffer));
return [value] { ImGui::TextUnformatted(value.c_str()); return value; };
},
[](const std::string &value, std::endian endian) -> std::vector<u8> {
hex::unused(endian);
return hex::crypt::encodeUleb128(std::strtoull(value.c_str(), nullptr, 0));
}
);
ContentRegistry::DataInspector::add("hex.builtin.inspector.bool", sizeof(bool),
[](auto buffer, auto endian, auto style) {
hex::unused(endian, style);

View File

@ -39,7 +39,7 @@ namespace hex::plugin::builtin {
if (this->m_validBytes < entry.requiredSize)
continue;
std::vector<u8> buffer(entry.requiredSize);
std::vector<u8> buffer(this->m_validBytes > entry.maxSize ? entry.maxSize : this->m_validBytes);
provider->read(this->m_startAddress, buffer.data(), buffer.size());
if (this->m_invert) {

View File

@ -426,6 +426,8 @@ namespace hex::plugin::builtin {
{ "hex.builtin.inspector.float", "float (32 bit)" },
{ "hex.builtin.inspector.double", "double (64 bit)" },
{ "hex.builtin.inspector.long_double", "long double (128 bit)" },
//{ "hex.builtin.inspector.sleb128", "Signed LEB128" },
//{ "hex.builtin.inspector.uleb128", "Unsigned LEB128" },
{ "hex.builtin.inspector.bool", "bool" },
{ "hex.builtin.inspector.ascii", "ASCII Zeichen" },
{ "hex.builtin.inspector.wide", "Wide Zeichen" },

View File

@ -431,6 +431,8 @@ namespace hex::plugin::builtin {
{ "hex.builtin.inspector.float", "float (32 bit)" },
{ "hex.builtin.inspector.double", "double (64 bit)" },
{ "hex.builtin.inspector.long_double", "long double (128 bit)" },
{ "hex.builtin.inspector.sleb128", "Signed LEB128" },
{ "hex.builtin.inspector.uleb128", "Unsigned LEB128" },
{ "hex.builtin.inspector.bool", "bool" },
{ "hex.builtin.inspector.ascii", "ASCII Character" },
{ "hex.builtin.inspector.wide", "Wide Character" },

View File

@ -429,6 +429,8 @@ namespace hex::plugin::builtin {
{ "hex.builtin.inspector.float", "float (32 bit)" },
{ "hex.builtin.inspector.double", "double (64 bit)" },
{ "hex.builtin.inspector.long_double", "long double (128 bit)" },
//{ "hex.builtin.inspector.sleb128", "Signed LEB128" },
//{ "hex.builtin.inspector.uleb128", "Unsigned LEB128" },
{ "hex.builtin.inspector.bool", "bool" },
{ "hex.builtin.inspector.ascii", "ASCII Character" },
{ "hex.builtin.inspector.wide", "Wide Character" },

View File

@ -430,6 +430,8 @@ namespace hex::plugin::builtin {
{ "hex.builtin.inspector.float", "float (32 bit)" },
{ "hex.builtin.inspector.double", "double (64 bit)" },
{ "hex.builtin.inspector.long_double", "long double (128 bit)" },
//{ "hex.builtin.inspector.sleb128", "Signed LEB128" },
//{ "hex.builtin.inspector.uleb128", "Unsigned LEB128" },
{ "hex.builtin.inspector.bool", "bool" },
{ "hex.builtin.inspector.ascii", "ASCII文字" },
{ "hex.builtin.inspector.wide", "Wide Character" },

View File

@ -427,6 +427,8 @@ namespace hex::plugin::builtin {
{ "hex.builtin.inspector.float", "float (32 bit)" },
{ "hex.builtin.inspector.double", "double (64 bit)" },
{ "hex.builtin.inspector.long_double", "long double (128 bit)" },
//{ "hex.builtin.inspector.sleb128", "Signed LEB128" },
//{ "hex.builtin.inspector.uleb128", "Unsigned LEB128" },
{ "hex.builtin.inspector.bool", "bool" },
{ "hex.builtin.inspector.ascii", "ASCII Character" },
{ "hex.builtin.inspector.wide", "Wide Character" },

View File

@ -431,6 +431,8 @@ namespace hex::plugin::builtin {
{ "hex.builtin.inspector.float", "float(32位单精度)" },
{ "hex.builtin.inspector.double", "double(64位双精度)" },
{ "hex.builtin.inspector.long_double", "long double(128位四精度)" },
//{ "hex.builtin.inspector.sleb128", "Signed LEB128" },
//{ "hex.builtin.inspector.uleb128", "Unsigned LEB128" },
{ "hex.builtin.inspector.bool", "bool" },
{ "hex.builtin.inspector.ascii", "ASCII 字符" },
{ "hex.builtin.inspector.wide", "宽字符" },

View File

@ -428,6 +428,8 @@ namespace hex::plugin::builtin {
{ "hex.builtin.inspector.float", "float (32 位元)" },
{ "hex.builtin.inspector.double", "double (64 位元)" },
{ "hex.builtin.inspector.long_double", "long double (128 位元)" },
//{ "hex.builtin.inspector.sleb128", "Signed LEB128" },
//{ "hex.builtin.inspector.uleb128", "Unsigned LEB128" },
{ "hex.builtin.inspector.bool", "bool" },
{ "hex.builtin.inspector.ascii", "ASCII 字元" },
{ "hex.builtin.inspector.wide", "框字元" },

View File

@ -12,6 +12,7 @@ set(AVAILABLE_TESTS
# Crypto
EncodeDecode16
EncodeDecode64
EncodeDecodeLEB128
CRC32
CRC32Random
CRC16

View File

@ -100,6 +100,67 @@ TEST_SEQUENCE("EncodeDecode64") {
TEST_SUCCESS();
};
TEST_SEQUENCE("EncodeDecodeLEB128") {
TEST_ASSERT(hex::crypt::encodeUleb128(0) == (std::vector<u8>{ 0 }));
TEST_ASSERT(hex::crypt::encodeUleb128(0x7F) == (std::vector<u8>{ 0x7F }));
TEST_ASSERT(hex::crypt::encodeUleb128(0xFF) == (std::vector<u8>{ 0xFF, 0x01 }));
TEST_ASSERT(hex::crypt::encodeUleb128(0xF0F0) == (std::vector<u8>{ 0xF0, 0xE1, 0x03 }));
TEST_ASSERT(hex::crypt::encodeSleb128(0) == (std::vector<u8>{ 0 }));
TEST_ASSERT(hex::crypt::encodeSleb128(0x7F) == (std::vector<u8>{ 0xFF, 0x00 }));
TEST_ASSERT(hex::crypt::encodeSleb128(0xFF) == (std::vector<u8>{ 0xFF, 0x01 }));
TEST_ASSERT(hex::crypt::encodeSleb128(0xF0F0) == (std::vector<u8>{ 0xF0, 0xE1, 0x03 }));
TEST_ASSERT(hex::crypt::encodeSleb128(-1) == (std::vector<u8>{ 0x7F }));
TEST_ASSERT(hex::crypt::encodeSleb128(-128) == (std::vector<u8>{ 0x80, 0x7F }));
TEST_ASSERT(hex::crypt::decodeUleb128({}) == 0);
TEST_ASSERT(hex::crypt::decodeUleb128({ 1 }) == 0x01);
TEST_ASSERT(hex::crypt::decodeUleb128({ 0x7F }) == 0x7F);
TEST_ASSERT(hex::crypt::decodeUleb128({ 0xFF }) == 0x7F);
TEST_ASSERT(hex::crypt::decodeUleb128({ 0xFF, 0x7F }) == 0x3FFF);
TEST_ASSERT(hex::crypt::decodeUleb128({
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x7F,
}) == ((static_cast<u128>(0xFFFF'FFFF'FFFF) << 64) | 0xFFFF'FFFF'FFFF'FFFF));
TEST_ASSERT(hex::crypt::decodeUleb128({ 0xAA, 0xBB, 0xCC, 0x00, 0xFF }) == 0x131DAA);
TEST_ASSERT(hex::crypt::decodeSleb128({}) == 0);
TEST_ASSERT(hex::crypt::decodeSleb128({ 1 }) == 0x01);
TEST_ASSERT(hex::crypt::decodeSleb128({ 0x3F }) == 0x3F);
TEST_ASSERT(hex::crypt::decodeSleb128({ 0x7F }) == -1);
TEST_ASSERT(hex::crypt::decodeSleb128({ 0xFF }) == -1);
TEST_ASSERT(hex::crypt::decodeSleb128({ 0xFF, 0x7F }) == -1);
TEST_ASSERT(hex::crypt::decodeSleb128({
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x7F,
}) == -1);
TEST_ASSERT(hex::crypt::decodeSleb128({ 0xAA, 0xBB, 0xCC, 0x00, 0xFF }) == 0x131DAA);
TEST_ASSERT(hex::crypt::decodeSleb128({ 0xAA, 0xBB, 0x4C }) == -0xCE256);
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<u8> data;
for (int i = 0; i < 1000; i++) {
std::vector<u8> original(sizeof(u128));
std::generate(std::begin(original), std::end(original), [&]() { return data(gen); });
u128 u = *reinterpret_cast<u128*>(original.data());
i128 s = *reinterpret_cast<i128*>(original.data());
auto encodedS = hex::crypt::encodeSleb128(s);
i128 decodedS = hex::crypt::decodeSleb128(encodedS);
auto encodedU = hex::crypt::encodeUleb128(u);
u128 decodedU = hex::crypt::decodeUleb128(encodedU);
TEST_ASSERT(decodedS == s, "encoded: {0} decoded: {1:X} original: {2:X}", encodedS, static_cast<u128>(decodedS), static_cast<u128>(s));
TEST_ASSERT(decodedU == u, "encoded: {0} decoded: {1:X} original: {2:X}", encodedU, decodedU, u);
}
TEST_SUCCESS();
};
struct CrcCheck {
std::string name;
int width;

View File

@ -29,4 +29,4 @@ TEST_SEQUENCE("ExtractBits") {
TEST_ASSERT(hex::extract(20, 35, 0x8899AABBCCDDEEFFU) == 0xBCCD);
TEST_SUCCESS();
};
};