cypher Posted January 9, 2014 Posted January 9, 2014 (edited) Hey there, as the available Scylla DLL by Aguila only supports dumping and I needed a good IAT fixing DLL/Lib, I made a wrapper around the Scylla source.Also because the available ImpRec DLL isnt such as easy to use as I wished. Check out the source on BitBucket https://bitbucket.org/cypherpunk/scylla_wrapper_dllor grab attached binaries:Debug x86Release x86Debug x64Release x64Its based on latest Scylla source. Basically it mimics all steps you do in the GUI version but also offers more detailed control if you need it. Features:IAT AutoSearchreading Importsvalidating Importscutting Imports (if the corresponding module would be empty, its cut too)fixing a DumpDumpingPE rebuilder Test it, report bugs and feature requests and I'll see what I can do. Also PullRequests on BitBucket are welcome ! Pretty easy to use, see below. What has been changed: - Native API calls (Nt*) replaced by WinAPI calls - stripped all WTL/ATL dependencies - stripped GUI (obviously) Exports -------- //searches IAT, writes to iatStart, iatSize int scylla_searchIAT(DWORD pid, DWORD_PTR &iatStart, DWORD &iatSize, DWORD_PTR searchStart, bool advancedSearch); //reads the imports, iatAddr is VA int scylla_getImports(DWORD_PTR iatAddr, DWORD iatSize, DWORD pid, LPVOID PVOID invalidImportCallback = NULL); //add a module manually, in case auto-search didnt get it, e.g scattered IAT bool scylla_addModule(const WCHAR* moduleName, DWORD_PTR firstThunkRVA); //add API manually, in case auto-search didnt get it, e.g scattered IAT bool scylla_addImport(const WCHAR* importName, DWORD_PTR thunkVA); //are all imports valid? bool scylla_importsValid(); //cut an Import, because its invalid or whatever reason. Calling this from within the invalidImportCallback will crash! //Call it after scylla_getImports call returned ! bool scylla_cutImport(DWORD_PTR apiAddr); //fix the dump int scylla_fixDump(WCHAR* dumpFile, WCHAR* iatFixFile); //fix a mapped dump int scylla_fixMappedDump(DWORD_PTR iatVA, DWORD_PTR FileMapVA, HANDLE hFileMap); //get imported DLL count int scylla_getModuleCount(); //get total API Imports count int scylla_getImportCount(); //enumerate imports tree void scylla_enumImportTree(LPVOID enumCallBack); //size which the new IAT will consume long scylla_estimatedIATSize(); //get thunkVA by API name DWORD_PTR scylla_findImportWriteLocation(char* importName); //get thunkVA by ordinal DWORD_PTR scylla_findOrdinalImportWriteLocation(DWORD_PTR ordinalNumber); //get API name by thunkVA, cast return to char* DWORD_PTR scylla_findImportNameByWriteLocation(DWORD_PTR thunkVA); //get DLL name by thunkVA, cast return to char* DWORD_PTR scylla_findModuleNameByWriteLocation(DWORD_PTR thunkVA); //dumps a process bool scylla_dumpProcessW(DWORD_PTR pid, const WCHAR * fileToDump, DWORD_PTR imagebase, DWORD_PTR entrypoint, const WCHAR * fileResult); bool scylla_dumpProcessA(DWORD_PTR pid, const char * fileToDump, DWORD_PTR imagebase, DWORD_PTR entrypoint, const char * fileResult); //rebuilds a files PE header bool scylla_rebuildFileW(const WCHAR * fileToRebuild, BOOL removeDosStub, BOOL updatePeHeaderChecksum, BOOL createBackup); bool scylla_rebuildFileA(const char * fileToRebuild, BOOL removeDosStub, BOOL updatePeHeaderChecksum, BOOL createBackup); Return Codes ------------- const BYTE SCY_ERROR_SUCCESS = 0; const BYTE SCY_ERROR_PROCOPEN = -1; const BYTE SCY_ERROR_IATWRITE = -2; const BYTE SCY_ERROR_IATSEARCH = -3; const BYTE SCY_ERROR_IATNOTFOUND = -4; Usage ------ typedef int (*SEARCHIAT) (DWORD, DWORD_PTR &, DWORD &, DWORD_PTR, bool); typedef int (*GETIMPORTS) (DWORD_PTR, DWORD, DWORD, LPVOID); typedef bool (*IMPORTSVALID) (); typedef int (*FIXDUMP) (WCHAR*, WCHAR*); HMODULE lib = LoadLibrary(_T("scylla_wrapper")); SEARCHIAT searchIAT = (SEARCHIAT) GetProcAddress(lib, "scylla_searchIAT"); GETIMPORTS getImports = (GETIMPORTS) GetProcAddress(lib, "scylla_getImports"); IMPORTSVALID importsValid = (IMPORTSVALID) GetProcAddress(lib, "scylla_importsValid"); FIXDUMP fixDump = (FIXDUMP) GetProcAddress(lib, "scylla_fixDump"); DWORD iatStart = 0xDEADBEEF; DWORD iatSize = 0xDEADBEEF; int search = searchIAT(fdProcessInfo->dwProcessId, iatStart, iatSize, eip, false); if(search==0) int imports = getImports(iatStart, iatSize, pid); bool valid = importsValid(); if(valid) int fix = fixDump(dumpFileName, IatFixFileName); Definitions ----------- typedef void*(*fCallback)(LPVOID invalidImport); //e.g. void* cbInvalidImport(void* apiAddr) typedef void(*fCallback)(LPVOID importDetail); typedef struct { bool NewDll; int NumberOfImports; ULONG_PTR ImageBase; ULONG_PTR BaseImportThunk; ULONG_PTR ImportThunk; char* APIName; char* DLLName; } ImportEnumData //e.g. pointer on this struct used in scylla_enumImportTree as argument void cbEnumImports(void* importDetail) { ImportEnumData* data = (ImportEnumData*)importDetail; } Notes ----- The pre-compiled binaries and project standard uses _cdecl calling convention. For assembly users, this means you have to push arguments from right-to-left onto the stack and clean the stack yourself after calling. #pragma pack(push,1) or compiler flag /Zp1 is needed for the struct members to be aligned correctlyBig shouts to Aguila for coding Scylla and making it OpenSource ! Edited April 4, 2014 by cypher 4
Dragon Palace Posted January 10, 2014 Posted January 10, 2014 hello, for od plugin or not? if yes, for od 1.10 or od 2.01?
ragdog Posted January 10, 2014 Posted January 10, 2014 This is not any plugin for olly or anything is only a dll interface for a project
Aguila Posted January 10, 2014 Posted January 10, 2014 improving/increasing the dll functions is a great idea, but I don't like the way you do it. My advice is:Use the recent source from here: https://github.com/NtQuery/Scylla/Check in the complete source without editing the source!Do your changes, but try to change only the necessary things. Try to keep the original source as complete as possible. Right now I don't know what you edited and your code is not future proof. What if I change something in scylla? It is really hard to adjust the changes to your code. Why did you strip the other dll exports? This doesn't make any sense.
cypher Posted January 10, 2014 Author Posted January 10, 2014 Hey Aguila, I agree with you. Changes to upstream need to be documented better. The original source is as complete and original as it can be. Only left out files it doesnt need. Changes can be easily copied over. What I edited was add stdafx include in every cpp removed references to Scylla Config and the GUI changed Native calls to WinAPI calls because otherwise when used from within a TitanEngine project, TE runs into an exception I could add Diff files if that helps? I didnt strip other DLL exports, I started this from scratch, so I am adding exports to it I can and will probably easily add the dumping functions. IAT AutoSearch is already done locally but not pushed up yet.
Aguila Posted January 10, 2014 Posted January 10, 2014 you dont need to write down or comment your changes. BUT the changes should be visible in the version control system... that is why I said, first commit everything and then begin to change it. I see that you created a new solution file, but I still wonder why you are doing this. I think it is a bad approach.
cypher Posted January 10, 2014 Author Posted January 10, 2014 Updated version in first post. IAT Autosearch support
Aguila Posted January 11, 2014 Posted January 11, 2014 here is now the official scylla dll with the 2 new dll functions. complete list of functions: BOOL __stdcall ScyllaDumpCurrentProcessW(const WCHAR * fileToDump, DWORD_PTR imagebase, DWORD_PTR entrypoint, const WCHAR * fileResult); BOOL __stdcall ScyllaDumpCurrentProcessA(const char * fileToDump, DWORD_PTR imagebase, DWORD_PTR entrypoint, const char * fileResult); BOOL __stdcall ScyllaDumpProcessW(DWORD_PTR pid, const WCHAR * fileToDump, DWORD_PTR imagebase, DWORD_PTR entrypoint, const WCHAR * fileResult); BOOL __stdcall ScyllaDumpProcessA(DWORD_PTR pid, const char * fileToDump, DWORD_PTR imagebase, DWORD_PTR entrypoint, const char * fileResult); BOOL __stdcall ScyllaRebuildFileW(const WCHAR * fileToRebuild, BOOL removeDosStub, BOOL updatePeHeaderChecksum, BOOL createBackup); BOOL __stdcall ScyllaRebuildFileA(const char * fileToRebuild, BOOL removeDosStub, BOOL updatePeHeaderChecksum, BOOL createBackup); const WCHAR * __stdcall ScyllaVersionInformationW(); const char * __stdcall ScyllaVersionInformationA(); DWORD __stdcall ScyllaVersionInformationDword(); int __stdcall ScyllaStartGui(DWORD dwProcessId, HINSTANCE mod); int __stdcall ScyllaIatSearch(DWORD dwProcessId, DWORD_PTR * iatStart, DWORD * iatSize, DWORD_PTR searchStart, BOOL advancedSearch); int __stdcall ScyllaIatFixAutoW(DWORD_PTR iatAddr, DWORD iatSize, DWORD dwProcessId, const WCHAR * dumpFile, const WCHAR * iatFixFile);Scylla_v0.93_dll.rar
cypher Posted January 11, 2014 Author Posted January 11, 2014 (edited) Updated version in first post. New features:- searchIAT- getImports- importsValid- fixDump Also the original Scylla DLL exports have been added:- dumpProcessW- dumpProcessA- rebuildFileW- rebuildFileA Edited January 11, 2014 by cypher
cypher Posted January 14, 2014 Author Posted January 14, 2014 Update: you can now fix a filemapped dump with fixMappedDump(DWORD_PTR iatVA, DWORD_PTR FileMapVA, HANDLE hFileMap); You have to map it yourself and it already needs to have enough space somewhere to store the new IAT. Either a new section or somewhere else.
LCF-AT Posted January 14, 2014 Posted January 14, 2014 Hi, question: So I try this functions now a little with MultiASM plugin just for testing a little. 1.) scylla_searchIAT function.So this will work so far to get the IAT start VA & size of a normal IAT but it will fail if the normal IAT was changed a little so then I get no datas back only in eax the value FC instead of 00 = success. 01001008 >77DCBA55 ADVAPI32.RegCreateKeyW 0100100C >FFFFFFFF <--- modded 01001010 >77DA7ABB ADVAPI32.RegQueryValueExA The question is why in this case I get no infos back about IAT start / size of the rest you know?So I think a another log parameter would be better to log the VA locations of not valid dwords + more diffrent return parameters in eax would be also a good idea. So a other problem with this API is if I add a another API normaly at the end of the IAT "or" if I just fill some APIs at the IAT top with 00 dwords and use again this API then I get again the same old results which are of course no more up to date = same IAT start VA and same IAT size.Why? 01001000 >00000000 <-- IAT start I filled just with 00 dwords 01001004 >00000000 01001008 >00000000 0100100C >00000000 01001010 >00000000 01001014 >77DA7852 ADVAPI32.RegOpenKeyExA 01001018 >77DAD767 ADVAPI32.RegSetValueExW 0100101C 00000000 01001020 >773AD270 COMCTL32.CreateStatusWindowW 01001024 00000000 01001028 >77F0DC61 GDI32.EndPage ............................. 01001340 >77C1806B msvcrt.wcsncpy 01001344 00000000 <-- Normal IAT end size = 344 01001348 77C1806B msvcrt.wcsncpy <--- I added one more 0100134C 00000000 <--- Next scan should get more size 01001350 00000000 Also it would be a good idea to add a custom function to fix single imports & different IAT blocks aerea's too = smart collect / prepair & fix method instead only to have a static basic method.Just only a idea of course. greetz
cypher Posted January 14, 2014 Author Posted January 14, 2014 (edited) 0xFC = -4 = SCY_ERROR_IATNOTFOUND, meaning scylla wasnt able to locate the IAT, maybe try a different searchStart parameter. For testing, I always let the "real" Scylla do the same searching/reading imports with same OEP like I used as startAddress (oep, codesectionAddr etc). The results should be the same, otherwise theres a bug in the wrapper. If not, either bug or unsupported in Scylla or you are doing sth wonky I cant answer you WHY it doesnt find it as the DLL only proxies to Scylla and this seems to be clearly sth about the search logic in scylla. Maybe Aguila can help. When searchIAT was successful however, you can use getImports to read the IAT, then call importsValid to see if all are fine. A callback and/or function for investigating/cutting invalid imports will probably be added somewhen in the near future. For your second example, assuming scylla found the correct size and start for the original IAT, you could simply modify iatsStart = iatStart - 0x340 and also iatSize and then use those modified values for getImports call. This should work as long as you added valid IAT entries... Edited January 14, 2014 by cypher
cypher Posted January 15, 2014 Author Posted January 15, 2014 (edited) @LCF-AT could you please try the PDB symbol file. If placed at the same place as the dll/lib, Olly should load it automatically and you should have more debug infos. This PDB is for the debug build. Maybe need to rename it to match the DLL name.If it works we can easily provide PDBs for this wrapper and for TitanEngine. not working Edited January 19, 2014 by cypher
Aguila Posted January 15, 2014 Posted January 15, 2014 @LCF-ATcypher's dll is not really usable in assembler. You should try the iat search function with my dll. Use the advanced search. call GetCurrentProcessIdpush eaxpush offset1push offset2push SomeAddressInCodeSectionpush 1 dwort ptr ds:[offset1] <- startdwort ptr ds:[offset2] <- size
cypher Posted January 15, 2014 Author Posted January 15, 2014 @Aguila, would you elaborate that please?My DLL doesnt do anything different to your DLL. It uses the exact same code. In fact you backported the functions from my DLL to yours, so what is the difference when using either one of the DLLs in assembler ?
cypher Posted January 16, 2014 Author Posted January 16, 2014 (edited) Update: - added a callback to getImports which will get called for every import that is invalid- added export cutImport(DWORD_PTR apiAddr) Usage:searchIATgetImports -> callback receives invalid API ptr address, return valid addr or 0 if you dont care now and save the addr for later useimportsValid -> false? -> iterate saved API addresses and call deleteAPIimportsValid -> should be true nowfixDumpNote: Dont dont dont call deleteAPI directly from within the callback!! Do that AFTER getImports call returned Edited January 16, 2014 by cypher
Aguila Posted January 16, 2014 Posted January 16, 2014 Usage of C++ datatypes in the exported function parameter list.cdecl calling convention
cypher Posted January 16, 2014 Author Posted January 16, 2014 cdecl calling convention Thanks for pointing this out. This means: - You will have to push arguments from right-to-left on the stack before calling - You will have to clean up the stack yourself after calling
sha0kahn Posted January 19, 2014 Posted January 19, 2014 So mate, I've now tried both versions of Scylla - Aguila's original .dll, and yours. I'm coding this little app in C#, and have of course declared the functions as such. Now, scylla_searchIAT, scylla_getImports, and scylla_importsValid are all working without any problems - but when it comes to the actual rebuilding, only error code I get is 254... Oh, and with the original Scylla .dll by Aguila - the error code is; IATFailed or something... Any suggestions to what I can do to solve this problem here? Also, I tried using the GUI function of the original Scylla - and that works flawlessly
cypher Posted January 19, 2014 Author Posted January 19, 2014 0xFE = -2 = SCY_ERROR_IATWRITE I cant help you much here as that return code directly comes from a call to the udnerlying Scylla code by Aguila. So maybe he can help.Its strange and unlikely however that the GUI does work when input parameters are the same, because the DLLs really mostly forward to the same internal functions.
sha0kahn Posted January 20, 2014 Posted January 20, 2014 uint iatStart = 0; uint iatSize = 0; ScyllaIAT.scylla_searchIAT(debugger.Process.Id, ref iatStart, ref iatSize, newOEP + debugger.ProcessImageBase, false); if (iatSize > 0) { SCYLLA_IATFIX_API getImps = ScyllaIAT.scylla_getImports(iatStart, iatSize, debugger.Process.Id); Console.WriteLine("IAT Start: " + iatStart.ToString("X8")); Console.WriteLine("IAT Size: " + iatSize.ToString("X8")); Console.WriteLine("getImports: " + getImps); if (ScyllaIAT.scylla_importsValid()) { SCYLLA_IATFIX_API check = ScyllaIAT.scylla_fixDump(dumpOpts.OutputPath, dumpOpts.OutputPath + "_fixed.exe", ".txte"); Console.WriteLine("fixDump: " + check.ToString()); } } As I said, everything works except the fixDump or IATFix function...
cypher Posted January 20, 2014 Author Posted January 20, 2014 have you tried tracing/stepping into the debug version of the dll ? Namely into this function scylla_fixDump(...) ... if (importRebuild.rebuildImportTable(fixedFilePath, moduleList)) //trace in herethat way we could better see what exactly fails while trying to fix it: not a valid PE, adding section, or actually writing the IAT into new section
cypher Posted January 20, 2014 Author Posted January 20, 2014 (edited) Updated version in first post. New features:getModuleCountgetImportCountenumImportTreeestimatedIATSizex64 builds now available with every new version Edited January 20, 2014 by cypher
cypher Posted January 21, 2014 Author Posted January 21, 2014 (edited) Updated version in first post New features:addModule //add a module manually, in case auto-search didnt get it, e.g scattered IATaddImport //add a module manually, in case auto-search didnt get it, e.g scattered IATfindImportWriteLocation //get thunkVA by API namefindOrdinalImportWriteLocation //get thunkVA by ordinalfindImportNameByWriteLocation //get API name by thunkVA, cast return to char*findModuleNameByWriteLocation //get DLL name by thunkVA, cast return to char*Thats it folks. No more features planned. Only on request and considered useful. And of course bugfixing! Edited January 21, 2014 by cypher
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now