The MASM Forum

Projects => ObjAsm => Topic started by: Biterider on August 24, 2023, 06:24:17 AM

Title: ResGuard for Framework C
Post by: Biterider on August 24, 2023, 06:24:17 AM
Hi
I just uploaded the updated version of ResGuard to the GitHub repo. Now it can also be compiled for 64 bit, but the frame analysis and forwarding did not work properly, however the 32 bit counterpart works as expected.
Reworking the existing code forced me to think again about all the details and I wrote a lot more comments to understand what I did in the next iteration of the code.  :biggrin:

For the 64-bit version, stackwalking is much more complicated and requires the use of additional information that is not on the stack. There are some APIs that make the task easier, like StackWalk64 (https://masm32.com/board/;https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-stackwalk64), but they need to be implemented properly, which will take a little more time.

To find leaks, the 32-bit version must be used for the time being.  :wink2:

Biterider

Title: Re: ResGuard for Framework C
Post by: Biterider on August 29, 2023, 05:52:13 AM
Hi
I tested the debug services for ResGuard and was really impressed with how useful they are, so I thought I should share it.  :cool:

At the moment, leaked resources are detected as before, but the call stack up to the API call that triggered the leak can be reconstructed and visualised in DebugCenter.
The current test environment shows, for example, the API name, the name of the calling procedure and the address where the call was made up to the start of the application.

──────────────────────────────────────────────────────────────────────
 • CreateBitmap « P2(00007FF789F748EEh)
                 « P1(00007FF789F7492Fh)
                  « P0(00007FF789F7494Ah)
                   « start(00007FF789F7517Eh)
 • CreateRectRgn « P2(00007FF789F74904h)
                  « P1(00007FF789F7492Fh)
                   « P0(00007FF789F7494Ah)
                    « start(00007FF789F7517Eh)
 • GlobalAlloc « StrAllocW(00007FF789F7670Bh)
                « StrNewW(00007FF789F754D1h)
                 « P2(00007FF789F74913h)
                  « P1(00007FF789F7492Fh)
                   « P0(00007FF789F7494Ah)
                    « start(00007FF789F7517Eh)
 • BeginPaint « OA_Application_OnPaint(00007FF789F74C1Eh)
               « OA_Window_WndProc(00007FF789F725F0h)
                « CallWindowProcW(00007FFDF4F8E858h)
                 « DispatchMessageW(00007FFDF4F8E3DCh)
                  « SendMessageTimeoutW(00007FFDF4FA0C33h)
                   « KiUserCallbackDispatcher(00007FFDF5D50E94h)
                    « NtUserCallHwndLock(00007FFDF3531464h)
                     « OA_Application_Init(00007FF789F74A2Ah)
                      « start(00007FF789F7518Fh)
──────────────────────────────────────────────────────────────────────

Unfortunately, the 32-bit API counterpart behaves a little differently, so the code path has to be changed.  :sad:

Regards, Biterider
Title: Re: ResGuard for Framework C
Post by: HSE on August 29, 2023, 06:46:28 AM
Hi Biterider,

Quote from: Biterider on August 29, 2023, 05:52:13 AMUnfortunately, the 32-bit API counterpart behaves a little differently, so the code path has to be changed.  :sad:

Old method with today long addresses don't look so good. Beside, with this more informative format, you could search in source code instead of only X64DBG disassemble :thumbsup:

HSE
Title: Re: ResGuard for Framework C
Post by: Biterider on August 29, 2023, 05:19:27 PM
Hi HSE
The "old" hooking method has proven to work perfectly on 32-bit and 64-bit targets, and that's a big deal. 
The stack tracing features provided by the operating system are the new additions that help effectively locate the API call that caused the leak or failed call.

The visualization is also important, but I am far from saying that this is the final version. It should just be a small taste. If there are any suggestions on this, they are very welcome. At the moment nothing is fixed and can be modeled as we like.  :thumbsup:

Biterider
Title: Re: ResGuard for Framework C
Post by: HSE on August 30, 2023, 09:21:09 AM
Hi Biterider,


Quote from: Biterider on August 29, 2023, 05:19:27 PMThe "old" hooking method has proven to work perfectly on 32-bit and 64-bit targets, and that's a big deal.

That work perfectly, pretty easy  :rolleyes:

Last time I "play", resource theoretically is released from linked list and collection, but still is counted like a leak  :biggrin:  :biggrin:

More to play  :thumbsup:

Quote from: Biterider on August 29, 2023, 05:19:27 PMIf there are any suggestions on this, they are very welcome.

:thumbsup:

HSE
Title: Re: ResGuard for Framework C
Post by: Biterider on August 30, 2023, 04:46:19 PM
Hi HSE
This is the new look and feel, which is more in line with the classic design.

Started
Leak Report:
Global Mem-Blocks:  cur. =   1, max. =     2, tot. =     3
 • GlobalAlloc ← StrAllocW(00007FF60B5C670Bh) ← StrNewW(00007FF60B5C54D1h) ← P2(00007FF60B5C4913h) ← P1(00007FF60B5C492Fh) ← P0(00007FF60B5C494Ah) ← start(00007FF60B5C517Eh)
Heap Mem-Blocks:    cur. =   1, max. =     1, tot. =     1
 • HeapAlloc ← P2(00007FF60B5C4719h) ← P1(00007FF60B5C492Fh) ← P0(00007FF60B5C494Ah) ← start(00007FF60B5C517Eh)
GDI Brushes:        cur. =   2, max. =     2, tot. =     2
 • CreateSolidBrush ← P2(00007FF60B5C486Ah) ← P1(00007FF60B5C492Fh) ← P0(00007FF60B5C494Ah) ← start(00007FF60B5C517Eh)
 • CreateSolidBrush ← P2(00007FF60B5C48C9h) ← P1(00007FF60B5C492Fh) ← P0(00007FF60B5C494Ah) ← start(00007FF60B5C517Eh)
GDI Bitmaps:        cur. =   1, max. =     1, tot. =     1
 • CreateBitmap ← P2(00007FF60B5C48EEh) ← P1(00007FF60B5C492Fh) ← P0(00007FF60B5C494Ah) ← start(00007FF60B5C517Eh)
GDI Regions:        cur. =   1, max. =     1, tot. =     1
 • CreateRectRgn ← P2(00007FF60B5C4904h) ← P1(00007FF60B5C492Fh) ← P0(00007FF60B5C494Ah) ← start(00007FF60B5C517Eh)
Failed API calls:   3
 • CreateFileW ← P2(00007FF60B5C4700h) ← P1(00007FF60B5C492Fh) ← P0(00007FF60B5C494Ah) ← start(00007FF60B5C517Eh)
 • CreateFileW ← P2(00007FF60B5C489Eh) ← P1(00007FF60B5C492Fh) ← P0(00007FF60B5C494Ah) ← start(00007FF60B5C517Eh)
 • DeleteObject ← P2(00007FF60B5C48BEh) ← P1(00007FF60B5C492Fh) ← P0(00007FF60B5C494Ah) ← start(00007FF60B5C517Eh)
Stopped

The catch with ResGuard is that it has to be updated with every OS update when new APIs are introduced. Fortunately, the old classic GDI and USER APIs are well covered.

Biterider
Title: Re: ResGuard for Framework C
Post by: HSE on August 31, 2023, 10:15:24 AM
Hi Biterider,

Quote from: Biterider on August 30, 2023, 04:46:19 PMThis is the new look and feel, which is more in line with the classic design.

Fantastic  :thumbsup:


Quote from: Biterider on August 30, 2023, 04:46:19 PMOS update when new APIs are introduced.

Really? I think I'm using same APIs available in Win95  :biggrin:

HSE
Title: Re: ResGuard for Framework C
Post by: Biterider on September 01, 2023, 09:27:56 PM
Hi
I have finished both code paths and will update the repo tonight. 
The code has the character of a beta version.  :cool:

I had to update the "model.inc" file to pass some parameters to the ResGuard system so that the stack would stop running at the boundary of the application and not enter the operating system.

It is important to know that symbolic information from the pdb file is required to display the procedure names. In the vast majority of cases this is not a problem, since the compilation target is always DEBUG when using ResGuard.

Another change is the introduction of a flag called SUFFIX in the SysSetup macro, which adds a "32" or "64" to the end of the generated files. The import lib takes this into account as well.

Biterider
Title: Re: ResGuard for Framework C
Post by: Biterider on September 02, 2023, 04:52:56 AM
Hi
Finally done, both code paths work the same. I have uploaded the complete code (still beta) for testing. The correct selection of the 32/64 bit DLL is done automatically. This means that the handling is identical to previous versions  :cool:

In the testing process I discovered a small bug on DebugCenter, that was also updated (ver 2.2.1).

Biterider
Title: Re: ResGuard for Framework C
Post by: Biterider on September 03, 2023, 09:16:40 PM
Hi
When adding some new APIs, I noticed that the system "named objects" need special handling and that the detour procedure has to pay attention to whether the name is local or global.

Affected are: named Pipes, Mailslots, WaitableTimers, FileMappings etc. 
As long as you do not reuse the names, they all work fine. The problem arises when the objects are reused with the same name.

The next version will take care of that.  :cool:

Biterider
Title: Re: ResGuard for Framework C
Post by: HSE on September 03, 2023, 11:37:17 PM
Hi Biterider,

Quote from: Biterider on September 03, 2023, 09:16:40 PMThe problem arises when the objects are reused with the same name.

You mean same name in different namespace ¿?

HSE
Title: Re: ResGuard for Framework C
Post by: Biterider on September 04, 2023, 04:01:38 AM
Hi HSE
It is easier to explain this with an example: CreateEventExA (https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createeventexa)

QuoteReturn value
If the function succeeds, the return value is a handle to the event object. If the named event object existed before the function call, the function returns a handle to the existing object and GetLastError (https://learn.microsoft.com/en-us/windows/desktop/api/errhandlingapi/nf-errhandlingapi-getlasterror) returns ERROR_ALREADY_EXISTS.
If the function fails, the return value is NULL. To get extended error information, call GetLastError (https://learn.microsoft.com/en-us/windows/desktop/api/errhandlingapi/nf-errhandlingapi-getlasterror).

In the case that you have called this API more than once with the same name, which is perfectly legal, ResGuard must be aware of this situation. Fortunately, the affected APIs return the same HANDLE for such calls. 
This way, the previous calls (and all associated information) can be discarded, leaving only the last call. 
Whether the names are local or global is less relevant, as I don't want to keep track of them.

Biterider

Title: Re: ResGuard for Framework C
Post by: HSE on September 04, 2023, 04:29:20 AM
Ok. A Windows object, like a window class in return of RegisterClass.  :thumbsup:

Thanks, HSE.
Title: Re: ResGuard for Framework C
Post by: Biterider on September 05, 2023, 07:21:37 PM
Hi
While reviewing the examples and projects from the ObjAsm project with the new ResGuard version, I noticed that there is a borderline case. This occurs when a system object handle is obtained in a non-standard way.

For example, when the WM_CTLCOLORSTATIC message is used with a control and it returns a brush that is deleted by accident. In this case, ResGuard tries internally to remove the call data when deleting the object, but does not find it and thus an error occurs. In the current ResGuard implementation, this case is considered a ResGuard internal error and an error message is issued.

Actually, this situation can be used to detect logic errors in the examined code. I can imagine introducing a new category to the 2 already existing ones: "Leaks", "Fails" and new "Logic errors".

Biterider
Title: Re: ResGuard for Framework C
Post by: HSE on September 06, 2023, 02:41:56 AM
Illogics?  :rolleyes:
Title: Re: ResGuard for Framework C
Post by: Biterider on September 07, 2023, 08:33:51 PM
Hi
Yesterday I found something when I was looking for a leak. 

I have not considered GDI+ until now and thus, everything that is allocated there as GDI system object, leads to a leak. It took me a long time to realize this, but now I have included some GDI+ APIs from the flat API. 

Of course I also have to consider other allocations in addition, but that will come a bit later.  :biggrin:

Biterider
Title: Re: ResGuard for Framework C
Post by: HSE on September 10, 2023, 09:47:24 AM
Hi Biterider!

Working perfectly in standard Masm64 SDK project :thumbsup:

I was sure about the introduction of some leaks in the codeedit project, but 497 is a little to much  :biggrin:

Regards, HSE.
Title: Re: ResGuard for Framework C
Post by: Biterider on September 10, 2023, 03:36:29 PM
Hi HSE
Quote from: HSE on September 10, 2023, 09:47:24 AMWorking perfectly in standard Masm64 SDK project
Thank you for checking this out.  :thumbsup:
I have prepared a demo in simple MASM, but it is only a demo and not real code. ResGuard is not finished yet, if it ever gets "finished". Today I want to add the rest of the GDI+ APIs. The rest will then be added bit by bit.


Quote from: HSE on September 10, 2023, 09:47:24 AMbut 497 is a little to much
That is absolutely true. It happened to me too, and it's overwhelming when you have a couple of leaks at the same time. I need to think of a way to reduce the output, for example by grouping all the leaks that were triggered at the same code address (just an idea).  :icon_idea:

Biterider
Title: Re: ResGuard for Framework C
Post by: Biterider on September 10, 2023, 08:14:08 PM
Hi HSE
I added the aggregation of calls and now the output looks much better. 
The number of calls is now shown in square brackets after the API name.

(https://i.postimg.cc/jDdy6cN2/image.png) (https://postimg.cc/jDdy6cN2)

Biterider
Title: Re: ResGuard for Framework C
Post by: HSE on September 11, 2023, 01:59:23 AM
Hi Biterder!

That look better  :thumbsup:

HSE
Title: Re: ResGuard for Framework C
Post by: Biterider on September 11, 2023, 02:10:17 AM
Hi
I just uploaded the new code with the aggregation code and the relevant GDI+ APIs.

Biterider
Title: Re: ResGuard for Framework C
Post by: HSE on September 11, 2023, 03:02:25 AM
 :thumbsup:

(https://i.postimg.cc/VJmgZsvW/resguard.jpg) (https://postimg.cc/VJmgZsvW)
Title: Re: ResGuard for Framework C
Post by: Biterider on September 12, 2023, 02:54:06 AM
Hi
There is still a problem with the current implementation. 

In the past, ResGuard would have been allowed to continue running after a Show command. However, now that we are doing the aggregation, this is no longer possible. 
I have not used ResGuard this way, but in the past it could have been done this way. 

To restore this state you need a slightly different strategy, which is quite possible, but will take some time to implement.

Biterider
Title: Re: ResGuard for Framework C
Post by: Biterider on September 14, 2023, 07:08:56 AM
Hi
I have completed the last update by adding and testing the reverse aggregation feature so that the original start/stop functionality is restored.  :wink2:

The update is uploaded to the repo.

Biterider
Title: Re: ResGuard for Framework C
Post by: Biterider on September 14, 2023, 09:44:43 PM
Hi
New update with the 2 APIs from this post from fearless
https://masm32.com/board/index.php?topic=11265.msg123856#msg123856 (https://masm32.com/board/index.php?topic=11265.msg123856#msg123856)

Biterider
Title: Re: ResGuard for Framework C
Post by: HSE on September 16, 2023, 12:08:25 AM
Hi Biterider!

Address that ResGuard show it's not call address (like old version, if I remember well). I presume now show invoke beginning. Is that correct?

Thanks in advance, HSE
Title: Re: ResGuard for Framework C
Post by: Biterider on September 17, 2023, 09:44:36 PM
Hi HSE
The address shown after the symbol name of the calling frame is the return address of the call instruction.
My original intention was to show the calling address, but I would need my own disassembler to decode the calling OP-code bytes. If you simply see the call instruction using a disassembler, it is easy to check what is happening.

BTW, it's the same thing that VS debugger shows.

Biterider
Title: Re: ResGuard for Framework C
Post by: Biterider on September 19, 2023, 05:24:57 AM
Hi
A stable version has been uploaded to the repository. 
The behaviour is now identical on 32- and 64-bit targets, despite the calling differences. 
The initialisation interface is now identical on both targets and a plain 32-bit MASM example has been added.
 
Full documentation will follow soon.  :cool:

Biterider