Findus bei den Mucklas

Intro

So long time ago me and my brother Kyle.. Oh wait

Long time ago I played this game “Findus bei den Mucklas” from the “Petterson and Findus” series. So to relive this nostalgia trip I decided some time ago to play it again. The problem: You can’t find shit in this economy for this game. After some searching I found the game but it didn’t start or something like that.

Fast forward to last week: I was cleaning some files and found the game lying on my hard drive. Okay why didn’t it work? Maybe we’ll find some new informations online. I found some posts but most we’re saying that you have to emulate Windows 2000/XP and then forward the hard drive - which would require one to buy a copy, which isn’t sold anymore…

If you just want to know how I got it to play, go to the end

Part 2: Betrayal

So I downloaded a XP iso from archive.org and installed it there. Using WinCDEmu I could mount the .img and install the game. After starting it, a promising logo showed up and destroyed my excitement by throwing a error: “Disc Error !”. Well what happened? Maybe some copy protection shittery? The internet didn’t answer. Well then let’s jump into Ghidra and look ourself.

We know that it’s a MessageBox, so let’s look for mentions of that:

  switch(reasonID) {
  case 2:
    uID = 0x3ea;
    break;
  case 3:
    bVar1 = true;
    uID = 0x3eb;
    break;
  default:
    uID = 0x3ec;
    break;
  case 6:
  case 7:
    uID = 0x3e9;
  }
  LoadStringA(instance,1000,local_120,0x20);
  LoadStringA(instance,uID,(LPSTR)local_100,0xff);
  iVar2 = MessageBoxA((HWND)0x0,(LPCSTR)local_100,local_120,bVar1 | 0x10);

One mention and it looks good. So LoadString, meaning the error is in the resources?

STRINGTABLE
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
{
  1000, 	"Application Error"
  1001, 	"This application cannot start as it cannot create needed files. There may not be enough free disk space."
  1002, 	"This application cannot run, as it could not find the shared library MSVCRT.DLL."
  1003, 	"This application requires the Shockwave 8 Player, which is not installed. Click OK to download it."
  1004, 	"This application cannot run."
}

That’s weird… No mention of the disc error. Where is the MessageBox called (Functions already named)?

  if (iVar2 == 0) {
    iVar2 = 7;
  }
  else {
    iVar2 = LoadMSVCRTModule(&local_20);
    if (iVar2 == 0) {
      iVar2 = LoadProjDllModule(&module,&local_1c);
      if (iVar2 == 0) {
        pFVar3 = GetProcAddress(module,s_ProjectorMain_2000806c);
        if (pFVar3 == (FARPROC)0x0) {
          iVar2 = 4;
        }
        else {
          local_18 = 1;
          local_14 = 0x18;
          if (DVar1 != 0) {
            local_10 = &LAB_200015f0;
            local_c = DVar1;
          }
          local_8 = DAT_20008ab0;
          local_4 = local_1c;
          iVar4 = (*pFVar3)(mainHandle,param_2,param_3,param_4,&local_18);
        }
      }
    }
  }
  
  ...
  
  MessageBoxExitReason((HINSTANCE)mainHandle,iVar2);
  

Okay so it wants to call a exported function from a module. And then complains about missing stuff… Looking through the rest of entry I didn’t find anything interesting. So maybe the check is done in this proj.dll:ProjectorMain? Well that file doesn’t exist next to the executable and google doesn’t say much. But what I see the shockwave player popping up. Does that mean the game has to do something with shockwave (which was similar to flash)?

It actually works?

Well yes. The game was made with Macromedia Director 8 Shockwave Studio (which is also written in the) and is basically just a glorified Shockwave player. This link told me that projectors just point into the starting direction and let Shockwave do the rest. So the real juice is in the other files, but they aren’t swf (which is flash) or filetypes I know.

In P3media I found the files like intro.dxr and credits.dxr. So how does one play those? This archive.org link has some example projectors that are apparently packed with the Director Installer. Using the 8.5 projector I could just select any file and start it! Ignoring the script errors which it threw out by the minute, I could play some simple game, but they were out of context and I wanted the full game…

So what file does the real projector start? Clicking through some files I found intro.dxr, which played the intro… and threw out a “Disc Error !”. Found you bitch.

Deep dive

On my travels through the interwebs I found this decompiler. But I thought “meh I don’t know these file types”. Well now I know better. Building it on a linux vm and dumping the intro file got me this “lingo” code in a few files. Here the interesting parts:

on exitFrame
  if soundBusy(2) = 1 then
    go(the frame)
  else
    go("slut")
  end if
end

Uh good start? what does this even mean…

on exitFrame
  go(1, "pofintro")
end

So a label?

on exitFrame me
  KollaCopyProt()
end

Is this swedish? Kolla is maybe call? But CopyProt() sounds good. Where is it though… In the inconspiciously named file Cast Interne BehaviorScript Call Copy-X CD protection DLL (OPTGRAPH.DLL).lingo I found the real stuff:

on exitFrame me
  if the platform contains "Mac" then
    nothing()
  else
    if Ok = 0 then
      alert("Disc Error !")
      avslutaSpelet()
    else
      if getReturnVal(me) <> 26079537 then
        alert("Disc Error !")
        avslutaSpelet()
      end if
    end if
  end if
end
...
on init me
  errstring = "Error setting up initdisplay function call: "
  if serialNumber <> "demo" then
    GLURegister("R100-71-82650534")
  end if
  initDisplaySetup = new(xtra("glu32"))
  if not objectp(initDisplaySetup) then
    Ok = 0
    errstring = errstring & "no instance of Glu32"
  else
    dllpath = the applicationPath & "Optgraph.dll"
    err = GLUNew(initDisplaySetup, dllpath, "initdisplay", "L", "V", 0, 0)
    if err <> 0 then
      Ok = 0
      errstring = errstring & GLUGetErrorString(initDisplaySetup, err)
    end if
  end if
end

I found the Glu32.x32 in the Xtras folder and the description (in a string) says “Calls Win32 DLL Functions”. Okay so it calls initdisplay in Optgraph.dll and changes Ok if it fails (and thereby causing the “Disc Error !” prompt). There are a few other mentions of Ok in the file but let’s hope it depends on the stuff in optgraph.dll cause I know how to change those files… But we could just check with a debugger if that dll gets called right? But that would require me to work in my shitty xp vm or run the game on my host.

Running the game on my host throws another error cause I don’t have the cd inserted. The error message is saved in Pettson3.ini, but where the fuck does the code to call that come from? Ghidra shows no mention of that file in the main executable. Detect It Easy (used to look for packers and other stuff) does show it in a “overlay”, which is apparently data attached the back of the executable.

Note: At this point I also found out that you can just run the pfointro.dxr and thereby bypass the intro check, but I wanted to bypass the check completely as I didn’t know if using another projector made any problems.

Overlay Unpacking

The overlay starts with the magic bytes 10JPQ which is apparently attributed to the “Adveractive Installer”, which I have no idea what is. Maybe this is also a false positive?

Okay this Overlay has in the first hundred bytes this

MZ..........ÿÿ..
¸.......@.......
................
............è...
..º..´.Í!¸.LÍ!Th
is program canno
t be run in DOS 
mode....$.......
...

So that’s a PE beginning… We can export the overlay with PE Tree (yes there are probably easier ways) and then remove the first few bytes to get a PE. Put it into ghidra and bam, we have code. The new file exports ProjectorMain and still no mention of Pettson3.ini in the strings. This looks like the proj.dll. So another overlay? I did this a few times and i got these files: proj.dll, dirapi.dll, iml.dll, msvcrt.dll The problem started with the fifth overlay:

NB10....Ú4g6....
E:\8337\vc98\sel
f\bin\x86\msvcrt
.pdb.XFIRfB..LPP
Apami........}!"
.@..............
.pamm...........
.....ÿÿÿÿÿÿÿÿÿÿÿ
ÿXFIRfB..Q!"....
...

So it starts with NB10, which I don’t know. XFIR is interesting though, because the .dxr files all started with RIFX. The decompiler also looks for mmap or imap, which would overlap with pamm and pami. But what happened here? Maybe it needs other endianness to make parsing easier during runtime?

Finding the cd check

Googling (more like duckduckgoing) a bit lead me to this unpacker (thanks to this SO answer) which dropped a kicker_010928_1153.dir for me, which contains the exact thing I unpacked like 5 times before. But this one also starts with XFIR. But wait .dir? Didn’t the decompiler say that it also supports those? A quick decompile later and I got 2 new lingo files. Here are the interesting parts:

...
    driveletter = checkpccdrompath()
    if not voidp(driveletter) then
      ...
    else
      alert(string(ini.alertmessage)) -- Alerts us here
      quit()
    end if
...

on checkpccdrompath
  seperator = the last char in the applicationPath
  drivelista = ["d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
  Retvar = VOID
  repeat with Drive in drivelista
    iscdrom = baDiskInfo(Drive, "type")
    if iscdrom = "CD-ROM" then
      path = Drive & ":" & seperator & "p3media"
      if checkoncd(path) then
        Retvar = Drive
      else
      end if
      return Retvar
    end if
  end repeat
end

on checkoncd path
  fileList = getfilesinfolder(path)
  iscd = 0
  if fileList.getOne("intro.dxr") or fileList.getOne("intro.dir") then
    iscd = 1
  end if
  return iscd
end

(For Windows) It basically checks if a CD-ROM exists which has a intro.dxr or intro.dir in the p3media folder. I don’t think it even calls that intro file.

Outlook

Now we have 2 paths we can go down:

  • Just use another Projector and run the game through that (may have problems)
  • Remove/bypass the Copy protection from optgraph.dll and maybe the cd check in the executable so you can run it from anywhere

I decided to go with the 1st route cause I’m lazy. I uploaded the img file here. You can run it with the Projector I linked above or through Flashpoint. The resolution is only 640x480 but I haven’t found a way yet to make it bigger.