Skip to content

Instantly share code, notes, and snippets.

@robbi5
Last active May 27, 2023 00:27
Show Gist options
  • Save robbi5/b4788655d087173be8df890b6311fc72 to your computer and use it in GitHub Desktop.
Save robbi5/b4788655d087173be8df890b6311fc72 to your computer and use it in GitHub Desktop.
epson pos printer firmware

Download and extract epson pos printer firmware

Note: you may need to append -A or -B to your ProductName, based on which wifi adapter you use. If you don't, try -A.

Get Firmware List

curl -X "POST" "https://www.epson-biz.com/api/firm/" \
     -H 'Content-Type: application/json' \
     -d $'{
  "Rev": "2",
  "FormatName": "TMFirm-Form",
  "CommServer": {
    "Command": "GetFileList",
    "ToolID": "TM Utility for Android"
  },
  "PrinterSpec": {
    "Product": {
      "SerialNo": "",
      "Language": "en",
      "Derivative": "",
      "ProductName": "TM-m30II-NT-A"
    }
  }
}'

Results in {"Version" : "03.19A ESC/POS,03.18A ESC/POS,03.16A ESC/POS,03.15A ESC/POS,03.14A ESC/POS,03.12A ESC/POS,03.11A ESC/POS,03.10A ESC/POS,03.09A ESC/POS,03.08A ESC/POS,03.07A ESC/POS,03.06A ESC/POS,03.05A ESC/POS,03.04A ESC/POS"}

Get Changelog

curl -X "POST" "https://www.epson-biz.com/api/firm/" \
     -H 'Content-Type: application/json' \
     -d $'{
  "Rev": "2",
  "FormatName": "TMFirm-Form",
  "CommServer": {
    "Command": "GetHistory",
    "ToolID": "TM Utility for Android"
  },
  "PrinterSpec": {
    "Product": {
      "SerialNo": "",
      "Language": "en",
      "Derivative": "",
      "ProductName": "TM-m30II-NT-A"
    }
  }
}'

Results in {"History" : "https://download.epson-biz.com/epson/epson_public_document.php?name=TM-m30II_en.pdf"}

Download firmware

curl -X "POST" "https://www.epson-biz.com/api/firm/" \
     -H 'Content-Type: application/json' \
     -d $'{
  "Rev": "2",
  "FormatName": "TMFirm-Form",
  "CommServer": {
    "Command": "GetFile",
    "Version": "03.19A ESC/POS",
    "ToolID": "TM Utility for Android"
  },
  "PrinterSpec": {
    "Product": {
      "SerialNo": "",
      "Language": "en",
      "Derivative": "",
      "ProductName": "TM-m30II-NT-A"
    }
  }
}' --output download_file.efx

Extract with binwalk

$ binwalk -e download_file.efx

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             Microsoft executable, portable (PE)
45244         0xB0BC          Zip archive data, at least v2.0 to extract, compressed size: 48705878, uncompressed size: 48698448, name: LH_m30II-H_.rcx
48751358      0x2E7E2FE       End of Zip archive, footer length: 22
48754696      0x2E7F008       Object signature in DER format (PKCS header length: 4, sequence length: 9997
48754817      0x2E7F081       Certificate in DER format (x509 v3), header length: 4, sequence length: 1421
48756242      0x2E7F612       Certificate in DER format (x509 v3), header length: 4, sequence length: 1710
48757956      0x2E7FCC4       Certificate in DER format (x509 v3), header length: 4, sequence length: 1712
48759672      0x2E80378       Certificate in DER format (x509 v3), header length: 4, sequence length: 1728
48761404      0x2E80A3C       Certificate in DER format (x509 v3), header length: 4, sequence length: 1819

In _download_file.efx.extracted is now a zip file for you to extract again (maybe binwalk also did that for you). You'll get a LH_m30II-H_.rcx crypted firmware binary.

Decrypt firmware binary

You need the extracted file name, eg. LH_m30II-H_.rcx and the salt, which can be obtained by binwalking it again:

$ binwalk LH_m30II-H_.rcx

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             OpenSSL encryption, salted, salt: 0x1468BE067C549A14

Execute the appended calc.java and fill filename and saltAsHex with the corresponding values. You could use https://www.jdoodle.com/online-java-compiler-ide/ for it, if you don't want a full JDK installation on your system. (There you may need commons-codec:commons-codec:1.15 as a maven module)

Copy the resulting key and iv from the output, eg.

key:
4124774d59bc5eb4ecf8679465b0d953a35d851f30be8a6a09aabf34569b6736
iv:
0140514ae8ae16d00449e35e0f632fb1

and bring it into an openssl command line to finally decrypt the file:

openssl enc -d -aes-256-cbc -K 4124774d59bc5eb4ecf8679465b0d953a35d851f30be8a6a09aabf34569b6736 -iv 0140514ae8ae16d00449e35e0f632fb1 < LH_m30II-H_.rcx > dec.rcx
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.digest.MessageDigestAlgorithms;
import java.security.MessageDigest;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
public class MyClass {
public static void main(String args[]) {
// FILL THESE WITH binwalk RESULTS:
String filename = "LH_m30II-H_.rcx";
String saltAsHex = "1468BE067C549A14";
// com.epson.epos2.printer.EfxExtractor.caesar(String filename)
char[] charArray = filename.toCharArray();
for (int i = 0; i < charArray.length; i++) {
charArray[i] = (char) (charArray[i] - 1);
if (charArray[i] <= 25) {
charArray[i] = (char) (126 - (25 - charArray[i]));
}
}
String caesar = String.valueOf(charArray);
System.out.println(caesar);
// com.epson.epos2.printer.EfxExtractor.createPassword(String filename)
String str2 = "";
for (int i = 0; i < Math.min(14, filename.length()); i++) {
str2 = (str2 + "GjsnxbsfVqebuf".charAt(i)) + caesar.charAt(i);
}
System.out.println(str2);
try {
byte[] salt = Hex.decodeHex(saltAsHex);
// com.epson.epos2.printer.EfxExtractor.createKey(String str, byte[] bArr)
byte[] bArr = salt;
str = str2;
byte[] bytes = str.getBytes("US-ASCII");
MessageDigest messageDigest = MessageDigest.getInstance(MessageDigestAlgorithms.MD5);
byte[] bArr2 = new byte[bytes.length + bArr.length];
System.arraycopy(bytes, 0, bArr2, 0, bytes.length);
System.arraycopy(bArr, 0, bArr2, bytes.length, bArr.length);
byte[] digest = messageDigest.digest(bArr2);
byte[] bArr3 = new byte[digest.length + bytes.length + bArr.length];
System.arraycopy(digest, 0, bArr3, 0, digest.length);
System.arraycopy(bytes, 0, bArr3, digest.length, bytes.length);
System.arraycopy(bArr, 0, bArr3, digest.length + bytes.length, bArr.length);
byte[] digest2 = messageDigest.digest(bArr3);
byte[] bArr4 = new byte[digest.length + digest2.length];
System.arraycopy(digest, 0, bArr4, 0, digest.length);
System.arraycopy(digest2, 0, bArr4, digest.length, digest2.length);
System.out.println("key:");
System.out.println(Hex.encodeHex(bArr4));
// com.epson.epos2.printer.EfxExtractor.createIv(String str, byte[] bArr)
byte[] bArr5 = new byte[digest2.length + bytes.length + bArr.length];
System.arraycopy(digest2, 0, bArr5, 0, digest2.length);
System.arraycopy(bytes, 0, bArr5, digest2.length, bytes.length);
System.arraycopy(bArr, 0, bArr5, digest2.length + bytes.length, bArr.length);
byte[] digest5 = messageDigest.digest(bArr5);
System.out.println("iv:");
System.out.println(Hex.encodeHex(digest5));
}
catch (DecoderException e) {}
catch (UnsupportedEncodingException e) {}
catch (NoSuchAlgorithmException e) {}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment