subtle warning, the content below is for educational purposes only. go back if you dont like this
also for this tutorial im using version 1.5.0 of macsfancontrol for compatibility purposes even tho the codebase is probably the same
as an avid user of this software (i still use it btw) something i hate is the fact the dev wasnt getting enough funds so he decided to make it a 14 day free trial with new releases... and because i cant support that let's learn how to reverse engineer this appstarting off, im going to be using this software because theres no obfuscation or aslr in releases before 1.5.9.. i think
im going to be trying to activate is as-is (video below.. hopefully) to give yoy an idea of how it handles the activation
we need to patch the license entering part, more specifically the unlock button since it seems that pressing it actually makes the software decide if it wants to let us do something or not
so let's start! loading a program is quite easy in x64dbg (even tho im using x32dbg... same thing just 32 bit) you just open it with the file > open dialog

i was greeted with this, and apparently you have to press F9 to run the program to it's entry point.. whatever that is
to search for string references inside the main module, you just have to right click the optionalheader.addressofentrypoint, and search for string references like this

i first went for the unlock button which was pretty easy to find and i set a breakpoint by hitting the little dot to the left of the address, making it red

so now when the unlock button has been initialized the program "breaks" making it way easier for me to see what happens before it initializes!!
scrolling up before the button initializes shows some qt connections and other stuff that isn't crucial, and an x86 TEST instruction, patching it does nothing either way from my experience
so it seems looking at what the unlock button does didn't help us at ALL, but remember, the program had to think before either showing the invalid license dialog or the "thank you for activating" dialog, so let's try searching for them by opening the "References" tab and typing them in! i typed invalidlicense because that was my first thought

and would you look at that! we have two references! let's select the invalidlicensetitle one because i think the title loads before the text does.

scrolling up to the previous instructions (yes, a disassembler works in a linear fashion, you learn it the hard way if you've NEVER used one) we see a conditional jump (the JMP instruction) that happens after we test the BL (low 8 bits in the ebx register thanks stackexchange), and we see that it's red, so the jump is taken. i think that's what causes the license validation to fail, since it's right before the program spitting out the window for the failed license check
so let's patch it! right click the instruction and hit "Assemble", like so
we are now in the Assemble window of the debugger, and we have the instruction right in the text box. since it's a conditional jump, and we want the program to not jump to the other instruction, what we should do is tell the processor to not operate for some time (a few nanoseconds), so we have to patch the conditional jump (JZ instruction) with a NOP (no operate) instruction! we can do that by simply deleting everything inside the program's text box and just writing "nop" there!

after

hit OK to encode the instruction and then after the test bl,bl instruction, there should now be two nop instructions.

now, if we run our program, we will see that upon putting any data inside the two boxes (valid data either way just put a random email in there) and hitting unlock, the unlock window appears! hooray! (if the program pauses or appears stuck, just hit the button to the left of the Pause button, should be an arrow pointing to the right, since we did set a breakpoint when the unlock button gets initialized.)
you might be wondering now: belzenia, if the unlock window is shown, then why am i still in the free version of the program?
that's a great question! we only patched the license verification, now we have to patch the other instruction inside the program that actually decides if we have "pro" or not, since we forced the window to open.
we can do that by searching for string references inside the program again! we go to the "References" tab inside the program and type "pro", more specifically we can type "pro-version" since that's how it's named internally.

we now have the addresses for the pro-version checks. they WILL appear different for you, but the debugger has a handy little option to filter through them ascendingly or descendingly, because we're all humans, unless you're an LLM, if so get off my site i have a strict policy for ai use
now, we have to find the first mention of the pro-version string, we can just hit the "Address" tab to filter through the addresses until we find the smallest one (you can just put them all through a hex to dec converter and pick the smallest one out of the bunch).
if we did that, we can now select the address and right click to follow it in the dump and disassembler OR just double click it it does the same thing (the dump is just a raw dump of the program, we don't need it, in your case it's probably in the bottom left followed by dump 2, 3,4 etc)
now, we see that before the pro-version push, there is a jump instruction, this time, it doesn't jump. but what if it did jump? or the cpu just did nothing before moving onto the push? we will see that before the jump there is a TEST instruction, and another conditional jump instruction, the JB instruction which will skip to the TEST instruction directly, so we can just patch the instruction after the TEST one with NOP, which again, does nothing. so let's do it! assembling again like we did to patch the activation
we patched that instruction, now if we switch back to the program and try to activate it, guess what happens!
we have successfully patched the program! but now we also have to save our changes to the program, since opening it in a debugger every time we want to use it is very time-consuming and also impractical, we can just patch the executable directly!
go to the File menu, and select Patch file like so

now we are probably in the patch file menu, it's always a good idea to save our work since we can go back to it at any time right?

just hit the Export button, save your patch somewhere, do note the file will have a 1337 extension to it
now, to patch the file definitively we just hit the Patch file button, and save the executable somewhere safe, but do make sure it's in the same folder as the program we're trying to patch also make it a different name!!!
and once we are done and have successfully saved both our patches and the patched program, we can close the debugger and delete the unpatched executable, renaming it back to the original like nothing happened (< optional but whatevs)
we have finished the patching! hooray!!!! we successfully saved nothing because who actually buys a license for a fan control program IMAGINE