Talk:Family Feud

From ModdingWiki
Jump to navigation Jump to search

Family Feud ESI research

(MOVED HERE FROM User talk:TheAlmightyGuru)

Hello! Checked disassembler code for the Family Feud Question Format. It's always "-33" (except for bytes 13 and 10 which are skipped and stays as is) it's just all unencrypted text written in uppercase. What makes you think there are should be an additional branch with "-1"? Thank you. CTPAX-X Team (talk) 07:27, 5 December 2020 (UTC)

Hi CTPAX-X Team. I reevaluated the encryption, and it looks like I did have a problem with it, but it does indeed have two forms of rotation. Initially, I was rotating the cipher text to lower case because it was the nearest to the original, but the game uses uppercase text for everything, so I changed it to rotate to the uppercase letters, which, as you pointed out, is 33 for everything. However, the branch existed in my code because various vowels in the ciphertext are rotated more than most of the text. My guess is that the developers did this to make the ciphertext harder to read, but it's a pretty sloppy job. At a rotation of 33, the vowels only rotate to the lowercase letter equivalent while everything else is uppercase. This can be solved by forcing everything to uppercase before displaying it, but, to truly understand the encryption, I think it's best to further rotate down those characters which are further rotated up. --TheAlmightyGuru (talk) 15:13, 7 December 2020 (UTC)
That's probably because vowels in the MICPRINT.ESI font file not at the same places where you'd expected them to be in the default ASCII character set. Here is a simple tool to decrypt font files (works with both font MICPRINT.ESI and MONO.ESI). You can open decrypted files with Hexapad and the following settings: View -> Sprite Search, width: 16, format: 1bpp, to check how font characters actually arranged.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

static uint8_t esi_key[] = {
  0xA8, 0xC3, 0xA9, 0xB1, 0xB9, 0xB8, 0xB4,
  0xD7, 0xCB, 0xCD, 0xC1, 0xD3, 0xCF, 0xCE
};

int main(void) {
uint8_t p[1629];
uint32_t i;
FILE *fl;
  fl = fopen("MICPRINT.ESI", "rb");
  if (!fl) { return(1); }
  fread(p, sizeof(p), 1, fl);
  fclose(fl);

  /* decrypt font data, each character always 16 bits (2 bytes) in width */
  for (i = 0x6D; i < 1629; i++) {
    p[i] ^= esi_key[(i - 0x6D) % sizeof(esi_key)];
  }

  fl = fopen("MICPRINT.DMP", "wb");
  if (!fl) { return(2); }
  fwrite(p, sizeof(p), 1, fl);
  fclose(fl);
  return(0);
}

CTPAX-X Team (talk) 17:52, 7 December 2020 (UTC)

Thanks for the decryption code! I was able to view the font files in Hexapad, but I think it's creating some artifacting by not eliminating the header of the file. I wrote a quick viewer and this is what I got out of MICPRINT.ESI.
MICPRINT.ESI.png
All the vowels look normal. I also noticed that the game doesn't do this for all vowels in the answers. For example, sometimes an "E" is shifted, sometimes it isn't. I don't see any obvious pattern. Also, if I ignore the shifted vowels when I encrypt new Q&A data, the game functions just fine. I think this was just a half-hearted attempt to deter people snooping in the files. --TheAlmightyGuru (talk) 18:44, 8 December 2020 (UTC)
Yes, Hexapad trying to represent the whole file as an image (with the header where, as I understand, characters width stored), but this tool may be very handy if you want to quickly check if something is an image file. About vowels - I double checked disassembled game code and also under debugger - it's always "-33". As I understand lowercase (not vowels only) used for marking characters which you can ommit on inpit. For example, file "QS16.FF" first question: "YOU EAT TOO MUCH OF, AND GET SICK", and first answer "CANDY~SWEETs~FUDGE" character "~" used as splitter between answers wich are in the same percentage category. While lowercase characters ("s" in this example) tells that both words "SWEET" and "SWEETS" will be accepted as correct answers. If you convert them to uppercase you're lost one of the correct answers or free space since you need to store both words "SWEET" and "SWEETS" in that case. CTPAX-X Team (talk) 11:16, 9 December 2020 (UTC)
I think you've mostly cracked it! I tested the game out a bit further and it looks like the lowercase letters aren't for omitted letters, but wildcards. For example, the first question in QS1.FF has an answer of "WEaLTH," however the game won't accept "WELTH," but it will accept "WEZLTH" or "WEQLTH" which is expected for a wildcard. The answer parser seems to have suffix variations hard-coded because I've tried combinations of -ING -ES -ED with various answers, and they often work even when the letters are all upper case. Thanks to you, I've updated my Family Feud Editor to now handle lower case letters properly (Link). It's open source, but please excuse the awful code, I made no attempt to make it elegant! Also, thanks for the link to Hexapad, it will surely come in handy in the future. --TheAlmightyGuru (talk) 18:43, 14 December 2020 (UTC)
Glad I can help. And great job on discovering a real purpose of the lowercased characters! I should apologize about misunderstanding with the vowels - I mixed up "vowels" with "umlauts" and other not-actually-letter characters - that's why I tried to look into the font files. I should have checked the actual word meaning in the dictionary. And if you want you may not credit me since you done all the work for the game formats by yourself. Also I take a peek into your source code and it's nice and easy to understand, so I think you should be more confident about it. CTPAX-X Team (talk) 19:54, 14 December 2020 (UTC)
I give credit where it's due. I wouldn't have deciphered as much if you weren't prodding me. By the way, how did you crack the XOR cipher in the ESI files? Also, you mentioned you were running the game under a debugger, what program were you using? --TheAlmightyGuru (talk) 21:35, 14 December 2020 (UTC)
I'm using DOSBox Debugger with the DOSBox Debugger helper tool - make sure you copy config from the last message in the second link to work with the latest 0.74-3 version of DOSBox Debugger. Some useful links: Reverse Engineering with DosBox Debugger, x86 Instruction Set Reference, TECH Help! 6 by Flambeaux Software in .CHM - last one will help to understand how DOS interrupts work (be aware that TechHelp! contains some typos and factual errors). Also note that you need to unpack game executable file with the UNP - an "Executable file restore utility" tool - it's not required, but will reduce debugging time since there won't be unpacking code and you may change any bytes in the executable file without breaking compression since there will be none. Actual decrypting code starts at offset 0x0000B21E in the unpacked executable file (filling esi_key[] byte by byte similar to what you did in you code at ESI Format). You can find this code by setting breakpoints to the the file open function "BP 21 3D" (int 21h, ah = 3Dh - refer to TechHelp! manual: "TECH Topic" - "DOS Functions QuickRef") and file read "BP 21 3F", after that you need one extra breakpoint on the memory change BPM #:# (#:# - segment:offset address where font file was readed) when you see that the game reads the font file (it's easy since it is a first file that game reads). CTPAX-X Team (talk) 09:50, 15 December 2020 (UTC)
Few additions to the ESI Format based on the Family Feud executable file workflow. First of all the game reads 109 byte header (I didn't check other games, so I don't know why you change it to 108 in the article) and after that game multiply Number of glyphs (note that Family Feud treat this byte as signed) with Bytes per glyph and read rest of the font data. So at least Family Feud font can't be extended since game works only with the fixed and limited table for characters widths in the header. CTPAX-X Team (talk) 09:46, 18 December 2020 (UTC)
The 108 was a mistake, thanks for the correction. Good thing the programmers use a signed byte for the number of glyphs so they could support a font with negative characters in it :-D! Luckily, Family Feud uses only uppercase letters (except for the trademark on the title screen, which is a simple hack), so the entire lowercase set of letters could be repurposed. Unfortunately, I still think translation would be difficult because of all the checks for suffix variations that won't work in foreign languages. For example, the game automatically trims answers ending with an s, so singular nouns will work, but many French words are made plural with the addition of -x, which I doubt the programmers coded for. I suppose translation might still be possible if the answers made more liberal use of lowercase letters. My purpose of doing this hack was for a friend who wanted to add a new set of English questions and answers, and, so far, it's working out for him. Thanks again for all the help! --TheAlmightyGuru (talk) 13:40, 18 December 2020 (UTC)
What's with the character rotation, by the way? I implemented it for loading, but I haven't found any examples of it in the wild so far, and I'm mot sure if there's any real point in implementing it in the save function of my editor. Is it just another obfuscation method to make it hard on hackers, or is there an actual purpose to it?
Oh, and there doesn't seem to be anything determining the amount of pixels padded between characters. CTPAX-X Team, you dug into the internal handling... do you know if that is that just part of the code that uses the files, rather than something that can be saved inside the files? -Nyerguds (talk) 10:22, 6 January 2021 (UTC)
"Character rotation" - you mean "-33"? It's just crypt / obfuscation to hide questions strings. About padding between characters - I don't really know, since font file header was read in one place and I didn't know where it was used later (there is no "memory on access" breakpoints type in the DOSBox Debugger). I will take a look, but can't promise anything. CTPAX-X Team (talk) 21:46, 7 January 2021 (UTC)
Oh, wow, it's hilarious. Family Feud (I didn't test any other games) actually replaces bytes at offset 0x0A, 0x0B and 0x0C in the font header with the static values 4, 1 and 1 for both fonts. Some relationship between font header fields and font rendering routine can be found below. I hope this helps. CTPAX-X Team (talk) 15:09, 8 January 2021 (UTC)
  // from sub_1C690() code
  ??? = BYTE_05_INT8 + BYTE_0C_INT8
  ??? = BYTE_04_INT8 - BYTE_00_INT8

  if (BYTE_03_INT8 == 1) {
    val = BYTE_0D_INT8[chr] + BYTE_0B_INT8
  } else {
    if (??? == ' ') { // space character?
      val = BYTE_0A_INT8;
    } else {
      val = BYTE_04_INT8 + BYTE_0B_INT8;
    }
  }

  // from sub_1A1A6() code
  if ((BYTE_02_INT8 <= something) && (something <= BYTE_02_INT8 + BYTE_01_INT8)) {
    return(something - BYTE_02_INT8);
  } else {
    return(-1);
  }
With "character rotation" I meant the byte at 0x02; according to the wiki article it shifts the indices of the symbols; the thing you just showed in that sub_1A1A6(). Are there any known files that actually use this system?
As for those static values 4, 1 and 1, that's some weird stuff. Do you know where I can find these in the exe file? If they use a premade piece of code for displaying the font, it might be worth messing with these values to see what the in-game effect is.
By the way, it may be useful to move this research to the talk page of the actual ESI format. That said, I put this page on my watch list but got no notification of it getting edited...
-Nyerguds (talk) 19:33, 23 January 2021 (UTC)
I don't know about 0x02 byte, but as you can see from the code above it's used with the byte 0x01 (BYTE_01_INT8 - total glyph number in font file). So I guess 0x02 - probably first character code in font file starting from space (32) that's why it's equal to 1 since space skipped - see sub_1A1A6() code above - it's return font character index if I understand this part of code correctly.
In the sub_1389B (unpacked Family Feud executable MAIN.EXE file offset: 0x000038CB) at loc_138FE there are four arguments pushed on stack before call to sub_1A2D2: font_number (either 0 for "micprint.esi" or 1 for "mono.esi") and three arguments: 1, 4, 1. As you may see sub_1A2D2 called twice: for first (0) and second (1) font files.
And yes, could you move this whole discussion to at least Family Feud discussion page? Thank you!
As for page notification I just bookmarked Special:RecentChanges to easy see what's new.
- CTPAX-X Team (talk) 11:23, 24 January 2021 (UTC)
Well, the stuff that's known so far can be viewed and saved in my dev version of Westwood Font Editor, so I'll probably make a new release of that soon. As always, thanks for the help. --Nyerguds (talk) 11:45, 24 January 2021 (UTC)