Just because I don't care doesn't mean I don't understand.
682 stories
·
3 followers

Defeating a 40-year-old copy protection dongle

1 Comment

image

That’s right — this little device is what stood between me and the ability to run an even older piece of software that I recently unearthed during an expedition of software archaeology.

For a bit more background, I was recently involved in helping a friend’s accounting firm to move away from using an extremely legacy software package that they had locked themselves into using for the last four decades.

This software was built using a programming language called RPG (“Report Program Generator”), which is older than COBOL (!), and was used with IBM’s midrange computers such as the System/3, System/32, and all the way up to the AS/400. Apparently, RPG was subsequently ported to MS-DOS, so that the same software tools built with RPG could run on personal computers, which is how we ended up here.

This accounting firm was actually using a Windows 98 computer (yep, in 2026), and running the RPG software inside a DOS console window. And it turned out that, in order to run this software, it requires a special hardware copy-protection dongle to be attached to the computer’s parallel port! This was a relatively common practice in those days, particularly with “enterprise” software vendors who wanted to protect their very important™ software from unauthorized use.

image

Sadly, most of the text and markings on the dongle’s label has been worn or scratched off, but we can make out several clues:

  • The words “Stamford, CT”, and what’s very likely the logo of a company called “Software Security Inc”. The only evidence for the existence of this company is this record of them exhibiting their wares at SIGGRAPH conferences in the early 1990s, as well as several patents issued to them, relating to software protection.
  • A word that seems to say “RUNTIME”, which will become clear in a bit.

My first course of action was to take a disk image of the Windows 98 PC that was running this software, and get it running in an emulator, so that we could see what the software actually does, and perhaps export the data from this software into a more modern format, to be used with modern accounting tools. But of course all of this requires the hardware dongle; none of the accounting tools seem to work without it plugged in.

Before doing anything, I looked through the disk image for any additional interesting clues, and found plenty of fascinating (and archaeologically significant?) stuff:

image

  • We’ve got a compiler for the RPG II language (excellent!), made by a company called Software West Inc.
  • Even better, there are two versions of the RPG II compiler, released on various dates in the 1990s by Software West.
  • We’ve got the complete source code of the accounting software, written in RPG. It looks like the full accounting package consists of numerous RPG modules, with a gnarly combination of DOS batch files for orchestrating them, all set up as a “menu” system for the user to navigate using number combinations. Clearly the author of this accounting system was originally an IBM mainframe programmer, and insisted on bringing those skills over to DOS, with mixed results.

I began by playing around with the RPG compiler in isolation, and I learned very quickly that it’s the RPG compiler itself that requires the hardware dongle, and then the compiler automatically injects the same copy-protection logic into any executables it generates. This explains the text that seems to say “RUNTIME” on the dongle.

The compiler consists of a few executable files, notably RPGC.EXE, which is the compiler, and SEU.EXE, which is a source editor (“Source Entry Utility”). Here’s what we get when we launch SEU without the dongle, after a couple of seconds:

image

A bit rude, but this gives us an important clue: this program must be trying to communicate over the parallel port over the course of a few seconds (which could give us an opportunity to pause it for debugging, and see what it’s doing during that time), and then exits with a message (which we can now find in a disassembly of the program, and trace how it gets there).

A great tool for disassembling executables of this vintage is Reko. It understands 16-bit real mode executables, and even attempts to decompile them into readable C code that corresponds to the disassembly.

image

And so, looking at the decompiled/disassembled code in Reko, I expected to find in and out instructions, which would be the telltale sign of the program trying to communicate with the parallel port through the PC’s I/O ports. However… I didn’t see an in or out instruction anywhere! But then I noticed something: Reko disassembled the executable into two “segments”: 0800 and 0809, and I was only looking at segment 0809.

image

If we look at segment 0800, we see the smoking gun: in and out instructions, meaning that the copy-protection routine is definitely here, and best of all, the entire code segment is a mere 0x90 bytes, which suggests that the entire routine should be pretty easy to unravel and understand. For some reason, Reko was not able to decompile this code into a C representation, but it still produced a disassembly, which will work just fine for our purposes. Maybe this was a primitive form of obfuscation from those early days, which is now confusing Reko and preventing it from associating this chunk of code with the rest of the program… who knows.

Here is a GitHub Gist with the disassembly of this code, along with my annotations and notes. My x86 assembly knowledge is a little rusty, but here is the gist of what this code does:

  • It’s definitely a single self-contained routine, intended to be called using a “far” CALL instruction, since it returns with a RETF instruction.
  • It begins by detecting the address of the parallel port, by reading the BIOS data area. If the computer has more than one parallel port, the dongle must be connected to the first parallel port (LPT1).
  • It performs a loop where it writes values to the data register of the parallel port, and then reads the status register, and accumulates responses in the BH and BL registers.
  • At the end of the routine, the “result” of the whole procedure is stored in the BX register (BH and BL together), which will presumably be “verified” by the caller of the routine.
  • Very importantly, there doesn’t seem to be any “input” into this routine. It doesn’t pop anything from the stack, nor does it care about any register values passed into it. Which can only mean that the result of this routine is completely constant! No matter what complicated back-and-forth it does with the dongle, the result of this routine should always be the same.

With the knowledge that this routine must exit with some magic value stored in BX, we can now patch the first few bytes of the routine to do just that! Not yet knowing which value to put in BX, let’s start with 1234:

BB 34 12       MOV BX, 1234h
CB             RETF

Only the first four bytes need patching — set BX to our desired value, and get out of there. Running the patched executable with these new bytes still fails (expectedly) with the same message of “No dongle, no edit”, but it fails immediately, instead of after several seconds of talking to the parallel port. Progress!

Stepping through the disassembly more closely, we get another major clue: The only value that BH can be at the end of the routine is 76h. So, our total value for the magic number in BX must be of the form 76xx. In other words, only the BL value remains unknown:

BB __ 76       MOV BX, 76__h
CB             RETF

Since BL is an 8-bit register, it can only have 256 possible values. And what do we do when we have 256 combinations to try? Brute force it! I whipped up a script that plugs a value into that particular byte (from 0 to 255) and programmatically launches the executable in DosBox, and observes the output. Lo and behold, it worked! The brute forcing didn’t take long at all, because the correct number turned out to be… 6. Meaning that the total magic number in BX should be 7606h:

BB 06 76       MOV BX, 7606h
CB             RETF

image

Bingo!
And then, proceeding to examine the other executable files in the compiler suite, the parallel port routine turns out to be exactly the same. All of the executables have the exact same copy protection logic, as if it was rubber-stamped onto them. In fact, when the compiler (RPGC.EXE) compiles some RPG source code, it seems to copy the parallel port routine from itself into the compiled program. That’s right: the patched version of the compiler will produce executables with the same patched copy protection routine! Very convenient.

I must say, this copy protection mechanism seems a bit… simplistic? A hardware dongle that just passes back a constant number? Defeatable with a four-byte patch? Is this really worthy of a patent? But who am I to pass judgment. It’s possible that I haven’t fully understood the logic, and the copy protection will somehow re-surface in another way. It’s also possible that the creators of the RPG compiler (Software West, Inc) didn’t take proper advantage of the hardware dongle, and used it in a way that is so easily bypassed.

In any case, Software West’s RPG II compiler is now free from the constraint of the parallel port dongle! And at some point soon, I’ll work on purging any PII from the compiler directories, and make this compiler available as an artifact of computing history. It doesn’t seem to be available anywhere else on the web. If anyone reading this was associated with Software West Inc, feel free to get in touch — I have many questions!

Adblock test (Why?)

Read the whole story
jgbishop
21 hours ago
reply
Cool story!
Durham, NC
Share this story
Delete

Buzz

2 Shares

Two sleepy kidney beans are awoken at 5:31 in the morning. Banging a pan with a spoon and jumping on the bed is their child, a coffee bean.

The post Buzz appeared first on The Perry Bible Fellowship.

Read the whole story
jgbishop
2 days ago
reply
Durham, NC
Share this story
Delete

Microsoft is experimenting with a top menu bar for Windows 11

1 Comment and 2 Shares

Microsoft's PowerToys team is contemplating building a top menu bar for Windows 11, much like Linux, macOS, or older versions of Windows. The menu bar, or Command Palette Dock as Microsoft calls it, would be a new optional UI that provides quick access to tools, monitoring of system resources, and much more.

Microsoft has provided concept images of what it's looking to build, and is soliciting feedback on whether Windows users would use a PowerToy like this. "The dock is designed to be highly configurable," explains Niels Laute, a senior product manager at Microsoft. "It can be positioned on the top, left, right, or bottom edge of the scree …

Read the full story at The Verge.

Read the whole story
jgbishop
2 days ago
reply
This is interesting. The PowerToys team usually develops the coolest stuff ... someone at Microsoft needs to put them in charge.
Durham, NC
Share this story
Delete

Django: profile memory usage with Memray

1 Comment

Memory usage can be hard to keep under control in Python projects. The language doesn’t make it explicit where memory is allocated, module imports can have signficant costs, and it’s all too easy to create a global data structure that accidentally grows unbounded, leaking memory. Django projects can be particularly susceptible to memory bloat, as they may import many large dependencies like numpy, even if they’re only used in a few places.

One tool to help understand your program’s memory usage is Memray, a memory profiler for Python created by developers at Bloomberg. Memray tracks where memory is allocated and deallocated during program execution. It can then present that data in various ways, including spectucular flame graphs, collapsing many stack traces into a chart where bar width represents memory allocation size.

Profile a Django project

Memray can profile any Python command with its memray run command. For a Django project, I suggest you start by profiling the check management command, which loads your project and then runs system checks. This is a good approximation of the minimum work required to start up your Django app, imposed on every server load and management command execution.

To profile check, run:

$ memray run manage.py check
Writing profile results into memray-manage.py.4579.bin
System check identified no issues (0 silenced).
[memray] Successfully generated profile results.

You can now generate reports from the stored allocation records.
Some example commands to generate reports:

/.../.venv/bin/python3 -m memray flamegraph memray-manage.py.4579.bin

The command completes as normal, outputting System check identified no issues (0 silenced).. Around that, Memray outputs information about its profiling, saved in a .bin file featuring the process ID, and a suggestion to follow up by generating a flame graph.

The flame graph is great, so go ahead and make it:

$ memray flamegraph memray-manage.py.4579.bin
Wrote memray-flamegraph-manage.py.4579.html

The result is a .html file you can open in your browser, which will look something like this:

Memray flame graph of Django check command

The header of the page contains some controls, along with a mini graph tracking resident and heap memory over time. Underneath it is the main flame graph, showing memory allocations over time.

By default, the graph is actually an “icicle” graph, with frames stacked downward like icicles, rather than upward like flames. This matches Python’s stack trace representation, where the most recent call is at the bottom. Toggle between flame and icicle views with the buttons in the header.

The Stats button at the top opens a dialog with several details, including the peak memory usage:

Memray stats dialog

Frames in the graph display the line of code running at the time, and their width is proportional to the amount of memory allocated at that point. Hover a frame to reveal its details: filename, line number, memory allocated, and number of allocations:

Memray flame graph frame details

Make an improvement

In the above example, I already narrowed in on a potential issue. The line from numpy.random import ... allocates 5.7 MB of memory, about 23% of the peak usage of 25.2 MB. This import occurs in example/utils.py, on line 3. Let’s look at that code now:

from colorsys import hls_to_rgb

from numpy.random import MT19937, Generator


def generate_icon_colours(number: int) -> list[str]:
    """
    Generate a list of distinct colours for the given number of icons.
    """
    colours = []
    for i in range(number):
        hue = i / number
        lightness = 0.5
        saturation = 0.7

        rgb = hls_to_rgb(hue, lightness, saturation)
        hex_colour = "#" + "".join(f"{int(c * 255):02x}" for c in rgb)
        colours.append(hex_colour)

    Generator(MT19937(42)).shuffle(colours)

    return colours

The code uses the Generator.shuffle() method from numpy.random to shuffle a list of generated colours. Since importing numpy is costly, and this colour generation is only used in a few code paths (imagine we’d checked), we have a few options:

  1. Delete the code—this is always an option if the function isn’t used or can be replaced with something simpler, like pregenerated lists of colours.

  2. Defer the import until needed, by moving it within the function:

    def generate_icon_colours(number: int) -> list[str]:
        """
        Generate a list of distinct colours for the given number of icons.
        """
        from numpy.random import MT19937, Generator
    
        ...
    

    Doing so will avoid the import cost until the first time the function is called, or something else imports numpy.random.

  3. Use a lazy import:

    lazy from numpy.random import MT19937, Generator
    
    def generate_icon_colours(number: int) -> list[str]:
        ...
    

    This syntax should become available from Python 3.15 (expected October 2026), following the implementation of PEP 810. It makes a given imported module or name only get imported on first usage.

    Until it’s out, an alternative is available in wrapt.lazy_import(), which creates an import-on-use module proxy:

    from wrapt import lazy_import
    
    npr = lazy_import("numpy.random")
    
    
    def generate_icon_colours(number: int) -> list[str]:
        ...
        npr.Generator(npr.MT19937(42)).shuffle(colours)
        ...
    
  4. Use a lighter-weight alternative, for example Python’s built-in random.shuffle() function:

    import random
    
    ...
    
    
    def generate_icon_colours(number: int) -> list[str]:
        ...
        random.shuffle(colours)
        ...
    

In this case, I would go with option 4, as it avoids the heavy numpy dependency altogether, will provide almost equivalent results, and doesn’t need any negotiation about changing functionality. We will see an improvement in startup memory usage as long as no other startup code path also imports numpy.random.

After making an edit, re-profile and look for changes:

Memray flame graph of Django check command after optimization

In this case, it seems the change worked and memory usage has reduced. The flame graph looks like the right ~75% of the previous one, with “icicles” for regular parts of Django’s startup process, such as importing django.db.models and running configure_logging(). And the Stats dialog shows a lower peak value.

Memray stats dialog post optimization

A drop from 25.2 MB to 19.4 MB, or 22% overall reduction!

(If the change hadn’t worked, we would probably have revealed another module that is loaded at startup and imports numpy.random. Removing or deferring that import could then yield the saving.)

A Zsh one-liner to speed up checking results

If you use Zsh, you chain memray run, memray flamegraph, and opening the HTML result file with:

$ memray run manage.py check && memray flamegraph memray-*.bin(om[1]) && open -a Firefox memray-flamegraph-*.html(om[1])

This can really speed up doing multiple iterations measuring potential improvements. I covered the (om[1]) globbing syntax in this previous Zsh-specific post.

Fin

Have a pleasant walk down Memray lane,

—Adam

Read the whole story
jgbishop
2 days ago
reply
Cool looking tool.
Durham, NC
Share this story
Delete

Microsoft is working to rebuild trust in Windows

1 Comment and 2 Shares

Windows is in a weird spot. In its 40-year history, the operating system has weathered its fair share of missteps, but Windows 11 is testing the patience of its users in new ways. Persistent bugs, performance issues, intrusive prompts, ads, and bloatware have eroded the core Windows experience. Early system requirement decisions have also damaged trust among Microsoft's most loyal users, an erosion that's accelerated by the company's aggressive push into AI that doesn't always deliver on its promises.

Windows is at breaking point, and Microsoft knows it. Sources familiar with the company's plans tell me Windows engineers are now focusing on …

Read the full story at The Verge.

Read the whole story
jgbishop
4 days ago
reply
I wish Microsoft would just do something new. Leave all the compatibility baggage behind, and dream up a new kernel. It's a crime that in 2026 system updates take nearly an hour on some machines. No Linux install ever has that problem.
Durham, NC
Share this story
Delete

Doctors in Brazil using tilapia fish skin to treat burn victims

1 Comment

FORTAZELA, Brazil — In this historic city by the sea in northeast Brazil, burn patients look as if they've emerged from the waves. They are covered in fish skin — specifically strips of sterilized tilapia.

Doctors here are testing the skin of the popular fish as a bandage for second- and third-degree burns. The innovation arose from an unmet need. Animal skin has long been used in the treatment of burns in developed countries. But Brazil lacks the human skin, pig skin, and artificial alternatives that are widely available in the US.

The three functional skin banks in Brazil can meet only 1 percent of the national demand, said Dr. Edmar Maciel, a plastic surgeon and burn specialist leading the clinical trials with tilapia skin.

As a result, public health patients in Brazil are normally bandaged with gauze and silver sulfadiazine cream.

"It's a burn cream because there's silver in it, so it prevents the burns from being infected," said Dr. Jeanne Lee, interim burn director at the the regional burn center at the University of California at San Diego. "But it doesn't help in terms of debriding a burn or necessarily helping it heal."

READ MORE: First Look: Plumbing the mysteries of sweat to help burn patients cool their skin

The gauze-and-cream dressing must be changed every day, a painful process. In the burn unit at Fortaleza's José Frota Institute, patients contort as their wounds are unwrapped and washed.

Enter the humble tilapia, a fish that's widely farmed in Brazil and whose skin, until now, was considered trash. Unlike the gauze bandages, the sterilized tilapia skin goes on and stays on.

The first step in the research process was to analyze the fish skin.

"We got a great surprise when we saw that the amount of collagen proteins, types 1 and 3, which are very important for scarring, exist in large quantities in tilapia skin, even more than in human skin and other skins," Maciel said. "Another factor we discovered is that the amount of tension, of resistance in tilapia skin is much greater than in human skin. Also the amount of moisture."

In patients with superficial second-degree burns, the doctors apply the fish skin and leave it until the patient scars naturally. For deep second-degree burns, the tilapia bandages must be changed a few times over several weeks of treatment, but still far less often than the gauze with cream. The tilapia treatment also cuts down healing time by up to several days and reduces the use of pain medication, Maciel said.

Antônio dos Santos, a fisherman, was offered the tilapia treatment as part of a clinical trial after he sustained burns to his entire right arm when a gas canister on his boat exploded. He accepted.

"After they put on the tilapia skin, it really relieved the pain," he said. "I thought it was really interesting that something like this could work."

READ MORE: High-tech bandage wins $100K from Boston Marathon bombing survivor's family

The initial batches of tilapia skin were studied and prepared by a team of researchers at the Federal University of Ceará. Lab technicians used various sterilizing agents, then sent the skins for radiation in São Paulo to kill viruses, before packaging and refrigerating the skins. Once cleaned and treated, they can last for up to two years.

In the US, animal-based skin substitutes require levels of scrutiny from the Food and Drug Administration and animal rights groups that can drive up costs, Lee said. Given the substantial supply of donated human skin, tilapia skin is unlikely to arrive at American hospitals anytime soon.

But it may be a boon in developing countries.

"I'm willing to use anything that might actually help a patient," Lee said. "It may be a good option depending on what country you're talking about. But I also think the problem is that you need to find places that have the resources to actually process the skin and sterilize it, and make sure it doesn't have diseases."

In Brazil, in addition to the clinical trials, researchers are currently conducting histological studies that compare the composition of human, tilapia, pig, and frog skins. They are also conducting studies on the comparative costs of tilapia skin and conventional burn treatments. If clinical trials show continued success, doctors hope a company will process the skins on an industrial scale and sell it to the public health system.

This article is reproduced with permission from STAT. It was first published on Mar. 2, 2017. Find the original story here.

A free press is a cornerstone of a healthy democracy.

Support trusted journalism and civil dialogue.

Adblock test (Why?)

Read the whole story
jgbishop
11 days ago
reply
What an interesting idea!
Durham, NC
Share this story
Delete
Next Page of Stories