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:
parent
64f962dbb2
commit
eca5fb894f
@ -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();
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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" },
|
||||
|
@ -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" },
|
||||
|
@ -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" },
|
||||
|
@ -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" },
|
||||
|
@ -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" },
|
||||
|
@ -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", "宽字符" },
|
||||
|
@ -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", "框字元" },
|
||||
|
@ -12,6 +12,7 @@ set(AVAILABLE_TESTS
|
||||
# Crypto
|
||||
EncodeDecode16
|
||||
EncodeDecode64
|
||||
EncodeDecodeLEB128
|
||||
CRC32
|
||||
CRC32Random
|
||||
CRC16
|
||||
|
@ -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;
|
||||
|
@ -29,4 +29,4 @@ TEST_SEQUENCE("ExtractBits") {
|
||||
TEST_ASSERT(hex::extract(20, 35, 0x8899AABBCCDDEEFFU) == 0xBCCD);
|
||||
|
||||
TEST_SUCCESS();
|
||||
};
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user