{"id":15115056,"url":"https://github.com/trustedsec/VerifyELF","last_synced_at":"2025-09-27T19:31:31.334Z","repository":{"id":238696992,"uuid":"794287130","full_name":"trustedsec/VerifyELF","owner":"trustedsec","description":null,"archived":false,"fork":false,"pushed_at":"2024-05-06T20:17:13.000Z","size":39,"stargazers_count":23,"open_issues_count":0,"forks_count":3,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-12-24T14:22:11.405Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/trustedsec.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-04-30T20:28:26.000Z","updated_at":"2024-11-19T15:48:58.000Z","dependencies_parsed_at":"2024-05-07T16:00:56.363Z","dependency_job_id":null,"html_url":"https://github.com/trustedsec/VerifyELF","commit_stats":null,"previous_names":["trustedsec/verifyelf"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trustedsec%2FVerifyELF","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trustedsec%2FVerifyELF/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trustedsec%2FVerifyELF/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trustedsec%2FVerifyELF/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/trustedsec","download_url":"https://codeload.github.com/trustedsec/VerifyELF/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234453724,"owners_count":18835113,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-09-26T01:43:40.013Z","updated_at":"2025-09-27T19:31:26.051Z","avatar_url":"https://github.com/trustedsec.png","language":"C","funding_links":[],"categories":["C"],"sub_categories":[],"readme":"# Verify Elf\n\nThis is a repository of a set of PoC (Proof of Concept) elf parsing and validation \nprograms. The goal is simply to validate that there are no hooks installed into the \nrunning processes, and if there are to print out that there is and what offset the \nfirst difference is, or print out all differences.\n\n## Binaries/Scripts\nThere are 3 source files:\n- `memloader_verifygot.c`\n    - This is the code that will identify GOT hooks, its seperate simply because to do this properly I need to load all the libraries of the remote process into mine, and fully load the binary inside my own process, resolve the symbols, identify the offset from the loaded base, and then calculate the remote library location based off the library at its base address.\n- `parseELF_validate_sections.c`\n    - This is the code that will validate all sections in a remote running process. This will identify hooks installed at function prologues or hollowed out shared objects.\n- `enumerate_maps.c`\n    - This is a single function and structure used to just parse /proc/\u003cpid\u003e/maps and return all libraries loaded and permissions.\n\n\n## Usage\nTo run over your system, you need to build and run these as root.\n\n### Building\n```\nmake\n```\n\n### Verify Sections\nTo validate all sections of every process, you can run \n```\ncd ./bins/\n./parseELF_validate_sections.out all \u003e /tmp/outputfile.txt\n```\nthen grep for lines with \"differ\" in it. Note this uses 100% of 1 cpu core.\n\n### Verify GOT Entries\nThis one will find things like the xz-utils backdoor. You can run it on a single process with \n\n```\ncd ./bins/\npython3 hook_scan_wrapper.py -p PID\n\u003cOR\u003e\n./memloader_test.out PID\nParsing input file, all entries should be verified\nBytes are the addresses, convert to little endian when verifying:\n\nDiffers offset: 0xe03f8:  (accept)                      \u003c------ Example of true positive \n        Legit :10 74 32 81 FE 70 00 00 \n        Remote:9B 3A D1 81 FE 70 00 00 \n```\n\nor run it over all processes (could have lots of results, will want to save to output file.\n\n```\ncd ./bins/\npython3 hook_scan_wrapper.py \u003e /tmp/outputfile.txt\n\u003canalyze manually here\u003e\n```\n\n## Identifying Common False Positives vs True Positives\nSome of the common false positives examples are going to be here.\n\n### Example of True Positive (XZ-Utils backdoor)\n```\npython3 hook_scan_wrapper.py \u003cSSHD_PID\u003e\nDiffers offset: 0x108208:  (RSA_public_decrypt)\n        Legit :40 82 92 BA 7B 7F 00 00\n        Remote:90 7A 3F BA 7B 7F 00 00\n```\n\n### Remote GOT has all or almost all 00's\nThis can be caused by either loading later on, or being an internal symbol only. \nOr it doesn't reslove properly.\n```\nDiffers offset: 0x113fc0:  (__stop_SYSTEMD_STATIC_DESTRUCT)\n        Legit :00 A0 CE FE E3 5A 00 00\n        Remote:00 00 00 00 00 00 00 00                  \u003c----- Note the NULLs here\n\nDiffers offset: 0x631ff0:  (stderr)\n        Legit :46 02 00 00 77 00 00 00\n        Remote:48 26 63 00 00 00 00 00\n```\n\n### Resolving symbols from wrong library or wrong symbol version \nSymbol versions can explain some differences, brave does it for log/log2/pow, can manually \nverify by looking up the address of each, and then `objdump -x \u003clibraryPath\u003e|grep \u003csymbolName\u003e` \nand seeing if theres multiple versions.\n\n```\nDiffers offset: 0x318d20:  (g_array_set_clear_func)\n        Legit :10 2A 9F 9B AF 73 00 00                  \u003c----- \n        Remote:10 FA 84 9B AF 73 00 00                  \u003c-----\nDiffers offset: 0x3193e0:  (g_array_remove_range)\n        Legit :00 2D 9F 9B AF 73 00 00\n        Remote:00 FD 84 9B AF 73 00 00\nDiffers offset: 0x319448:  (g_array_remove_index)\n        Legit :80 2A 9F 9B AF 73 00 00\n        Remote:80 FA 84 9B AF 73 00 00\nDiffers offset: 0x3197c0:  (g_array_get_element_size)\n        Legit :40 2A 9F 9B AF 73 00 00\n        Remote:40 FA 84 9B AF 73 00 00\nDiffers offset: 0x319cc0:  (g_array_remove_index_fast)\n        Legit :C0 2B 9F 9B AF 73 00 00\n        Remote:C0 FB 84 9B AF 73 00 00\n```\n\n### Symbol didn't try to resolve and relocation didn't apply properly\n```\nDiffers offset: 0x3f90:  ()                         \u003c--- Note the missing name in ()\n        Legit :00 50 71 72 6C 5A 00 00\n        Remote:D0 FA 5B 7D 63 7D 00 00\n```\n\n\n## Things to Note\nThese programs have some false positives, I tried to reduce them down or make them \neasier to identify based off the output\n\n- wtext sections in opengl: nvidia *SEEM* to overwrite these wtext sections, so these I highlight as false positives.\n- GOT hooks: Some processes use RUNPATH/RPATH to load up shared objects, I try to handle these the best I can, but if I can't load the shared object its possible these end up NULL and will show as differences.\n- GOT hooks: Some libraries export symbols that are duplicates to the legit one we want to load, and the way I'm loading with dlopen/dlsym don't resolve it the same way that ld does, so sometimes there will be false postives there.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrustedsec%2FVerifyELF","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftrustedsec%2FVerifyELF","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrustedsec%2FVerifyELF/lists"}