Page 1 of 2

Protecting our work from unauthorised distribution

Posted: Thu Nov 10, 2022 5:14 pm
by Oso
Hello all. I wondered if any other PB developers have given thought to ways of protecting our work, if the work is distributed, for instance by use of a licence code to unlock the software we have developed.

If someone with a decompiler were to reverse the executable, would it be possible to see that our source had been written in PureBasic? In what form would the decompiled code appear and how close to the original code would this be? I'm trying to understand, if a licence code method were to be used, whether that is secure. Thanks.

Re: Protecting our work from unauthorised distribution

Posted: Thu Nov 10, 2022 7:21 pm
by mk-soft
There is no secure licence code method. Each one can be cracked.
It is better to write good programmes where users are happy to pay and not to bother with any licence code.

The results of the pbcompiler have similarities in every programme. Hence the problem that PureBasic programs are declared as viruses again and again and have to send the PB programs as false positives to the antivirus creators.

Re: Protecting our work from unauthorised distribution

Posted: Fri Nov 11, 2022 12:07 am
by BarryG
PureBasic compiles to machine code in the end, so it won't look like a PureBasic source file, no.

But see here if using 32-bit PureBasic -> viewtopic.php?f=7&t=64919

Re: Protecting our work from unauthorised distribution

Posted: Fri Nov 11, 2022 7:32 am
by Oso
BarryG wrote: Fri Nov 11, 2022 12:07 am PureBasic compiles to machine code in the end, so it won't look like a PureBasic source file, no.
Thanks BarryG and mk-soft for the replies. Yes, I expected assembler code would be output, but what interested me was the extent to which that assembler code could be identified against lines of PureBasic code. In actual fact from trying this today, I can honestly say that it looks extremely difficult to make any sense of the object code and it seems almost impossible to identify a known string within the code. Below is the kind of code it outputs. For a most minimal PB EXE of 7Kbytes, there are pages upon pages of machine-level instructions, like this...

Image
BarryG wrote: Fri Nov 11, 2022 12:07 am But see here if using 32-bit PureBasic -> viewtopic.php?f=7&t=64919
Yes, I read that post. It begins with an assumption that the name of the author is embedded in the EXE, which turned out not to be the case — the author's name was in fact identified by the malware detection tool as the developer of Scintilla, so in other words a false positive.
mk-soft wrote: Thu Nov 10, 2022 7:21 pm There is no secure licence code method. Each one can be cracked.
I understand it is possible. I think what is important, is the level of difficulty required. From what I have tried today, it seems very difficult. The tool I used is x64dbg, which appears to be a popular debugger. I found x64dbg to be very buggy indeed, but it shows me how difficult it is to decypher the object code. It opens/executes the code and you can step through it, following each machine instruction. It is hugely complex, considering that my PB programme has no conditional logic. That PB code is below. Remarkably, in no place in the assembler can I find the string "Hello", though a hex editor tool can find the Unicode string... 48 00 65 00 6C 00 6C 00 6F which is H e l l o

Code: Select all

OpenConsole()
PrintN("Hello")

Re: Protecting our work from unauthorised distribution

Posted: Fri Nov 11, 2022 8:48 am
by Bitblazer
Oso wrote: Fri Nov 11, 2022 7:32 am
BarryG wrote: Fri Nov 11, 2022 12:07 am PureBasic compiles to machine code in the end, so it won't look like a PureBasic source file, no.
Thanks BarryG and mk-soft for the replies. Yes, I expected assembler code would be output, but what interested me was the extent to which that assembler code could be identified against lines of PureBasic code. In actual fact from trying this today, I can honestly say that it looks extremely difficult to make any sense of the object code and it seems almost impossible to identify a known string within the code. Below is the kind of code it outputs. For a most minimal PB EXE of 7Kbytes, there are pages upon pages of machine-level instructions, like this...

Image
BarryG wrote: Fri Nov 11, 2022 12:07 am But see here if using 32-bit PureBasic -> viewtopic.php?f=7&t=64919
Yes, I read that post. It begins with an assumption that the name of the author is embedded in the EXE, which turned out not to be the case — the author's name was in fact identified by the malware detection tool as the developer of Scintilla, so in other words a false positive.
mk-soft wrote: Thu Nov 10, 2022 7:21 pm There is no secure licence code method. Each one can be cracked.
I understand it is possible. I think what is important, is the level of difficulty required. From what I have tried today, it seems very difficult. The tool I used is x64dbg, which appears to be a popular debugger. I found x64dbg to be very buggy indeed, but it shows me how difficult it is to decypher the object code. It opens/executes the code and you can step through it, following each machine instruction. It is hugely complex, considering that my PB programme has no conditional logic. That PB code is below. Remarkably, in no place in the assembler can I find the string "Hello", though a hex editor tool can find the Unicode string... 48 00 65 00 6C 00 6C 00 6F which is H e l l o

Code: Select all

OpenConsole()
PrintN("Hello")
You need more serious tools like Ida pro.

I don't know what you used to look at your binary, but you need to look into the data segment. For better understanding, read the portable executable format description and check out the PE explorer.

Yes, you can identify a purebasic executable and yes, you could even create a compilable source version from your binary (see ps).

A purebasic Decompiler is absolutely possible. It just would be a lot work :)

The amount of work is simply serious and even protection systems of console creators have been broken after some months of work.

ps: don't get me wrong, it won't be your clean and easily readable source file, but a bit of a messy version filled with variables named like a14 or s12 and a lot will look like a mad scientist inplemented it while having a stroke ;) But it will compile to a similar working binary (mostly ;)

pps: you could always order a serious software protection from the creators of denuvo

Re: Protecting our work from unauthorised distribution

Posted: Fri Nov 11, 2022 10:21 am
by Oso
Bitblazer wrote: Fri Nov 11, 2022 8:48 am You need more serious tools like Ida pro.

I don't know what you used to look at your binary, but you need to look into the data segment. For better understanding, read the portable executable format description and check out the PE explorer.

Yes, you can identify a purebasic executable and yes, you could even create a compilable source version from your binary (see ps).

A purebasic Decompiler is absolutely possible. It just would be a lot work :)
[snipped]
Many thanks for the information Bitblazer, I appreciate all the detail on this subject. Let me first mention though, I have no intention of writing a decompiler. :D The reason this has come about is that I've been increasingly seeing examples on the web where people have attempted to make a video of the use of IDA (which you mention) and various similar tools. The presentations of these videos are very poor in quality, as they use rather contrived examples of their own compiled C code which contains a password, then use IDA to find the logic which checks the password and re-route the logic. This is of course infinitely more straightfoward in one's own code sample than it would be in a real software case and for this reason I think the videos are as near useless. Nevertheless, they got me thinking about software protection in general, because over the years I've had one or two paying clients where this has been abused.

Since the previous message, I have made further headway with this. What I found is that x64dbg (the tool I decided to quickly try) actually enters the code through ntdll.dll (not through the PureBasic compiled executable). This had caused me to think that the PB executable was massive, when in fact what I was looking at was ntdll.dll. If I press F9 to continue execution, it then enters my HELLO2.EXE routine, which is much smaller. Here is the code...

Code: Select all

0000000140001000 | 48:83EC 28               | sub rsp,28                              |
0000000140001004 | 49:C7C0 20000000         | mov r8,20                               | 20:' '
000000014000100B | 48:31D2                  | xor rdx,rdx                             | rdx:EntryPoint
000000014000100E | 48:B9 E453004001000000   | mov rcx,hello2.1400053E4                |
0000000140001018 | E8 E30F0000              | call <JMP.&memset>                      |
000000014000101D | 48:31C9                  | xor rcx,rcx                             |
0000000140001020 | E8 E10F0000              | call <JMP.&GetModuleHandleW>            |
0000000140001025 | 48:8905 C0430000         | mov qword ptr ds:[1400053EC],rax        | rax:EntryPoint
000000014000102C | 4D:31C0                  | xor r8,r8                               |
000000014000102F | 48:C7C2 00100000         | mov rdx,1000                            | rdx:EntryPoint
0000000140001036 | 48:31C9                  | xor rcx,rcx                             |
0000000140001039 | E8 CE0F0000              | call <JMP.&HeapCreate>                  |
000000014000103E | 48:8905 9F430000         | mov qword ptr ds:[1400053E4],rax        | rax:EntryPoint
0000000140001045 | E8 56120000              | call hello2.1400022A0                   |
000000014000104A | E8 0D100000              | call hello2.14000205C                   |
000000014000104F | 48:B8 2850004001000000   | mov rax,hello2.140005028                | rax:EntryPoint, 140005028:L"Hello"
0000000140001059 | 48:89C1                  | mov rcx,rax                             | rax:EntryPoint
000000014000105C | FF15 E63F0000            | call qword ptr ds:[140005048]           |
0000000140001062 | E8 1D000000              | call hello2.140001084                   |
0000000140001067 | E8 94120000              | call hello2.140002300                   |
000000014000106C | 48:8B0D 71430000         | mov rcx,qword ptr ds:[1400053E4]        |
0000000140001073 | E8 9A0F0000              | call <JMP.&HeapDestroy>                 |
0000000140001078 | 48:8B0D 75430000         | mov rcx,qword ptr ds:[1400053F4]        |
000000014000107F | E8 940F0000              | call <JMP.&ExitProcess>                 |
0000000140001084 | 48:83EC 28               | sub rsp,28                              |
0000000140001088 | 48:83C4 28               | add rsp,28                              |
000000014000108C | C3                       | ret                                     |
The line 014000104F which contains "Hello", interestingly doesn't contain the unicode HEX 48 00 65 00 6C 00 6C 00 6F 00. I have no idea why that is, but anyway it seems I was wrong earlier, when I said that the string cannot be found — it was because I was looking in ntdll.dll.

EDIT : It seems 140005028 is a memory location, perhaps containing 48 00 65 00 6C 00 6C 00 6F 00 of "Hello".

Re: Protecting our work from unauthorised distribution

Posted: Fri Nov 11, 2022 11:31 am
by spikey
Oso wrote: Fri Nov 11, 2022 10:21 am It seems 140005028 is a memory location, perhaps containing 48 00 65 00 6C 00 6C 00 6F 00 of "Hello".
Yes, the compiler gathers all strings in the program into a single table in the data segment (see Bitblazers post above). Pointers to the first byte of a particular string are then used as arguments to the function calls, in this case via RAX. Executable code is stored in a read only section as a primitive security measure against malware, separately from the strings which are stored in a writeable section. This is using the ASM backend, the C backend will go through a slightly different process of course but the end results should be more or less analogous. (I used pbcompiler /commented rather than a decompiler, and the string table values are in decimal, just for the record).

Code: Select all

OpenConsole()
PrintN("This is the string table!")
PrintN("Hello")

Code: Select all

...
public PureBasicStart
; 
section '.code' code readable executable align 4096
...
; OpenConsole()
  CALL   PB_OpenConsole
; PrintN("This is the string table!")
  MOV    rax,_S1
  MOV    rcx,rax
  CALL   qword [PB_PrintN]
; PrintN("Hello")
  MOV    rax,_S2
  MOV    rcx,rax
  CALL   qword [PB_PrintN]
...
section '.data' data readable writeable
; 
pb_align 8
public _SYS_StaticStringStart
_SYS_StaticStringStart:
_S1: dw 84,104,105,115,32,105,115,32,116,104,101,32,115,116,114,105,110,103,32,116,97,98,108,101,33,0
_S2: dw 72,101,108,108,111,0
...

Re: Protecting our work from unauthorised distribution

Posted: Fri Nov 11, 2022 12:59 pm
by Oso
spikey wrote: Fri Nov 11, 2022 11:31 am Yes, the compiler gathers all strings in the program into a single table in the data segment (see Bitblazers post above). Pointers to the first byte of a particular string are then used as arguments to the function calls, in this case via RAX. Executable code is stored in a read only section as a primitive security measure against malware, separately from the strings which are stored in a writeable section. This is using the ASM backend, the C backend will go through a slightly different process of course but the end results should be more or less analogous. (I used pbcompiler /commented rather than a decompiler, and the string table values are in decimal, just for the record).
Many thanks Spikey, it's good to gain some knowledge of what is going on in the executable. I also noticed that the test executable continued further after the previous example, showing more extensive code (there's 7 Kbytes in total). It drops to a memory location further on, which I suspect is more generalised code. I haven't included it as I accept that PB's developers might not wish for the internal code to be displayed openly, but it seems to be generic functions, like this...

Code: Select all

0000000140002000 | FF25 62310000            | jmp qword ptr ds:[<&memset>]            |
0000000140002006 | FF25 9C310000            | jmp qword ptr ds:[<&GetModuleHandleW>]  |
I think the feeling I get from looking at this, is that if we put an activation function into software that we write, then it's probably sufficient to conceal the logic. In other words, avoid using If activation$ = "ACTIVATE", because the string can be easily found, but split the logic up.

Re: Protecting our work from unauthorised distribution

Posted: Fri Nov 11, 2022 4:32 pm
by Paul
Oso wrote: Fri Nov 11, 2022 12:59 pm I think the feeling I get from looking at this, is that if we put an activation function into software that we write, then it's probably sufficient to conceal the logic. In other words, avoid using If activation$ = "ACTIVATE", because the string can be easily found, but split the logic up.
Have you read through any of the other similar threads... like this one?
viewtopic.php?t=75916

Re: Protecting our work from unauthorised distribution

Posted: Fri Nov 11, 2022 4:59 pm
by Oso
Paul wrote: Fri Nov 11, 2022 4:32 pm Have you read through any of the other similar threads... like this one?
viewtopic.php?t=75916
Thanks for posting that, no I hadn't seen it. Actually I'm not looking for a solution as draconian as that which was mentioned in the opening post. It refers to checking against an online database, which I think is really quite horrendous. We actually use a database product that has recently moved to online licensing, so that if the number of logged-in users exceeds the paid licence limit, the vendor's system automatically flags it as a licence violation.

I do think we need to protect our investment in time though. I don't see the need to make it absolutely impossible to hack, but simply a deterent.

Re: Protecting our work from unauthorised distribution

Posted: Fri Nov 11, 2022 5:23 pm
by Paul
Oso wrote: Fri Nov 11, 2022 4:59 pm Actually I'm not looking for a solution as draconian as that which was mentioned in the opening post. It refers to checking against an online database, which I think is really quite horrendous.
I was actually referring to the fact of how simple it can be to bypass a protection scheme by changing = to <> without having to waste time searching for or decoding a key string. :wink:


And I agree, a simple deterrent is great... but when more time is spent working on a deterrent than your actual software, that's when there is a problem. Remember to use your time wisely.

Re: Protecting our work from unauthorised distribution

Posted: Fri Nov 11, 2022 7:17 pm
by Oso
Paul wrote: Fri Nov 11, 2022 5:23 pm I was actually referring to the fact of how simple it can be to bypass a protection scheme by changing = to <> without having to waste time searching for or decoding a key string. :wink:
Yes, I noted the simplicity, but I'm sure that in practice we wouldn't write the code in a simple way, unlike the J.Baker example. It stores the string in the code, rather than calculating a hash from a serial number. I think we'd also split the secuity check into more than one place in the code — a check in a DLL perhaps, another in an screen launch and so on. Soon the hacker would be tired and lacking in morale to continue, at least I hope... :D

Re: Protecting our work from unauthorised distribution

Posted: Fri Nov 11, 2022 7:33 pm
by Bitblazer
Oso wrote: Fri Nov 11, 2022 7:17 pmI think we'd also split the secuity check into more than one place in the code — a check in a DLL perhaps, another in an screen launch and so on. Soon the hacker would be tired and lacking in morale to continue, at least I hope... :D
These methods are used for years now and didn't really change the outcome. It is simply a rat race. The hacking rat gets motivated by increasing complexity and better free puzzles though ;) Some people solve cross word puzzles, other solve technical problems. Anti hacking methods are just a fun complex puzzle to some - creating better puzzles (anti-hacking solutions) does not deter a hacker, it challenges and encourages them ;)

That's why technical magazines sometimes publish challenges with prices and why events like EUROPEAN CYBERSECURITY CHALLENGE and Pwn2own exists.

Re: Protecting our work from unauthorised distribution

Posted: Fri Nov 11, 2022 8:11 pm
by Oso
Bitblazer wrote: Fri Nov 11, 2022 7:33 pm These methods are used for years now and didn't really change the outcome. It is simply a rat race. The hacking rat gets motivated by increasing complexity and better free puzzles though ;) Some people solve cross word puzzles, other solve technical problems. Anti hacking methods are just a fun complex puzzle to some - creating better puzzles (anti-hacking solutions) does not deter a hacker, it challenges and encourages them ;)
To be honest I hadn't been aware of this sort of thing, but presumably some of it is related to diagnosis and resilience testing. From what I've seen so far, the reverse engineering tools seem to be marketed for investigating malware. The sort of work we do is usually for clients we know well, but even so, they sometimes try to bend the rules.

Re: Protecting our work from unauthorised distribution

Posted: Fri Nov 11, 2022 8:29 pm
by Bitblazer
Oso wrote: Fri Nov 11, 2022 8:11 pmthe reverse engineering tools seem to be marketed for investigating malware.
A tool is a tool is a tool. I have used both PE explorer and Ida Pro to verify suspected bugs in purebasic. But investigating malware gets a lot more public attention ;)