#include "exceptions.h" #include "providers.h" #include #include #include #include static void check(bool condition, const char *message) { if (!condition) throw std::runtime_error(message); } int main(int argc, char **argv) { try { if (argc != 2) throw std::runtime_error("bootstrap required"); for (const auto mode : {0, 1, 2, 3, 4}) { raven::ModuleSet modules; auto &module = modules.add("kernel32.dll", raven::environment_provider("kernel32.dll", 0x180000000)); raven::LoadedImage *images[] = {&module.loaded}; raven::NativeProcess process(images, argv[1], std::chrono::seconds(2)); const auto api = modules.resolve({"kernel32.dll", "RaiseException", 0, false, 0}); process.add_api_trap(api); std::vector bytes(15 * 8); for (size_t index = 0; index < bytes.size(); ++index) bytes[index] = static_cast(index * 7); const auto data = process.map_memory(4096, PROT_READ | PROT_WRITE); process.write_memory(data, bytes); const uint64_t arguments[] = {0x12345678e0123456ULL, 0x1234567800000001ULL, mode == 0 || mode == 4 ? 15U : mode == 3 ? 0U : 16U, mode == 2 ? 0 : mode == 3 || mode == 4 ? 1 : data}; check(process.call(api, arguments, std::chrono::seconds(1)).stop == raven::NativeStop::api, "exception fixture did not suspend at the API"); bool failed = false; std::optional captured; try { captured = raven::native_raise_exception(process); } catch (const std::runtime_error &) { failed = true; } check(failed == (mode == 1 || mode == 4), "software exception bounds or pointer rejection differs"); if (captured) { const auto &result = *captured; check(result.stop == raven::NativeStop::exception && result.value == 0xe0123456 && result.exception_flags == 1 && result.instruction == api, "software exception fields differ"); check(result.exception_information.size() == (mode == 0 ? 15U : 0U), "software exception parameter count differs"); if (!mode) for (size_t index = 0; index < bytes.size(); ++index) check(static_cast(result.exception_information[index / 8] >> ((index % 8) * 8)) == bytes[index], "software exception parameter bytes differ"); } const auto pending = process.api_arguments(4); check(std::equal(pending.begin(), pending.end(), std::begin(arguments)), "exception capture completed or altered the pending caller"); } for (const auto mode : {0,1,2,3}) { raven::ModuleSet modules; auto &module=modules.add("kernel32.dll",raven::environment_provider("kernel32.dll",0x180000000)); raven::LoadedImage *images[]{&module.loaded}; raven::NativeProcess process(images,argv[1],std::chrono::seconds(2)); const auto api=modules.resolve({"kernel32.dll","RaiseException",0,false,0}); process.add_api_trap(api); std::vector record(152); const auto put=[&](size_t at,uint64_t value,size_t width) { for (size_t byte=0; byte>(byte*8)); }; put(0,0xe0123456,4); put(4,1,4); put(16,0x190001234ULL,8); put(24,mode==2 ? 16 : 2,4); put(32,0x1122334455667788ULL,8); put(40,0x8877665544332211ULL,8); const auto data=process.map_memory(4096,PROT_READ | PROT_WRITE); process.write_memory(data,record); const uint64_t arguments[]{mode==0 ? 0x12345678e0123456ULL : mode==3 ? data+4096-128 : data}; check(process.call(api,arguments,std::chrono::seconds(1)).stop==raven::NativeStop::api,"RTL exception did not reach API boundary"); bool failed=false; std::optional result; try { result=raven::native_raise_rtl_exception(process,mode==0); } catch (const std::runtime_error &) { failed=true; } check(failed==(mode>=2),"RTL exception count/pointer bounds differ"); if (result) { check(result->stop==raven::NativeStop::exception && result->value==0xe0123456 && result->exception_flags==1, "RTL exception code/flags differ"); check(result->instruction==(mode==0 ? api : 0x190001234ULL),"RTL exception address differs"); check(result->exception_information==(mode==0 ? std::vector{} : std::vector{0x1122334455667788ULL,0x8877665544332211ULL}),"RTL exception information differs"); } check(process.api_arguments(1)[0]==arguments[0],"RTL exception capture changed the pending caller"); } std::cout << "Win32/RTL exception capture, DWORD ABI, record bounds and preserved pending callers passed\n"; return 0; } catch (const std::exception &error) { std::cerr << error.what() << '\n'; return 1; } }