How To Guides Files Links Toplists Forums


Please Vote for US!



Enter TopHackerz TOP Info Sites list and Vote for this site !!!

Enter to .com - The Top 100 Dss Info and Dealer Sites and Vote for this Site

Enter to TopSatSites and Vote for this Site!!!






Vote Now!

Enter to Sat-100.com and Vote for this Site!!!

Please Vote for US!




Syndrome Nagra2 cards, AVR-X Nagra2 cards





Part 1 Part 2 Part 3 Part 4 Exercises



This tutorial is being created due to requests from members of ADH who would
like to learn more about assembly language and more specifically TMS370 as
it relates to the P3. I am not an expert on tms370, but I do have many years
of experience programming in assembly and other higher level languages, so
bear with me as I will be learing as I go. I encourage everyone to
contribute and participate. Remember, anything we learn now will be useful as
we move into the next generation of smart cards.

disclamer: This information is for educational purposes only.


PART #1
Back to Top

Overview:

In programming, you are really only moving data from one location to
another, adding or performing some arithmetic function, comparing bits or
bytes, and jumping or branching based on those comparisons.

In summary, the most common used instructions are:

move
compare
add
branch/jmp

Using these simple statements and their variations, complex programs can be
written.

In TMS370, there are conventions in place and rules that must be followed
when actually coding these instructions. These rules mostly revolve around
how the opcodes and operands relate and how memory is addressed or accessed.


I will be referencing the TMS370 bible through out this tutorial.
spnu127a.pdf.
It can be found at: http://www.dssftp.com/Docs/hu-documentation.zip

Other important information including quick reference guides, sample
scripts, lessons, ROM dissassemblys, TMS370 assemblers and disassemblers are
here also. You will need this to follow along.

*** REQUIRED READING ..spnu127a.pdf pages: 488-519 - I suggest printing
these pages and placing in a notebook. The instruction set on pages from
520- are also needed and would be good for a notebook. Also print out the
opcode quick reference from the .zip file listed above.

--------------------------------------------------------------------------------

First off we need to define a few things:

An assembly language instruction contains an opcode and operands.

Below is an example of how an instruction may appear.

Label Instruction Operands Comment
XXXXX ADD #9,R3 ;comment

--------------------------------------------------------------------------------

There should be at least one space between each entry type. The label and
comment entries are optional.

The 73 instructions are supported by 246 opcodes that provide flexible
control
of CPU program flow. Some instructions use 16-bit opcodes, depending on the
type
of instruction and/or the addressing mode used.

EEprom - Electrically-Erasable Programmable Read-Only Memory. This is the
area of the smartcard that we can modify. (2000h-3FFFh on the P3)

ROM - Read only memory (C000-FFFF on the P3)


Registers:

Registers are generally thought of as high speed ram. Some registers allow
computations to be performed and are also used to temporarily store data for
testing, xoring and the like. On the tms370 platform, registers can be used
in pairs to address larger areas of memory and used to deal with 16 bit
values. Since we are dealing with 16 bit memory addresses and registers are
8 bits, we will need to use register pairs for addresssing the memory space.

There are also speacial function registers, bits are set or cleared in these
registers based on a calculation or comparison. They will be covered a
little later.

--------------------------------------------------------------------------------

Lets talk a little about the layout of the HU...

The EEprom is located at 2000-3FFFh. This area is divided into sections of
code
and data. Take a look the map below for some insight as to what these
locations
are used for.

Also, download supertweak 2.2 and place an HU bin in the same folder. Load
the
bin and step through the EEprom. ST2.2 will highlight and describes these
locations. Then use the "@" to disassemble at the cursor. (print & search
now
also..Thanks InDirect)

2000-2001 = 00 00
2002-2006 = Data, not the same on each CAM
2007-200F = Data, same on each CAM
2010-2010 = 03 (5th byte of ATR)
2014-2015 = Fuse Bytes
2018-201F = Data used to calc. last 8 bytes of ATR
2020-2023 = Data, same for each CAM
2024-2105 = PPV area
2106-22F1 = Tier area
2406-2407 = Spending Limit
2408-240B = Activation Date
240C-240F = Password
2410-2415 = 55 and Zip Code
2418-241A = PPV Slot 1 Guide 00 01 00
241B-241B = PPV Slot 1 Purchase Option
241C-241D = PPV Amount Purchased
241E-241F = PPV Spending Limit
2420-2425 = More PPV Info ???
2460-2463 = IRD number (Location 1)
2464-2464 = Rating Limit
2465-2465 = 00 Used to calc. 4th byte of ATR
24A4-24A7 = IRD number (Location 2)
24C0-24C7 = EEPROM Decrypt Key 1
24C8-24C9 = USW
24D8-24DB = CAM ID Number
24DC-24DC = CAM Checksum Byte
24E0-24E0 = Time Zone
2511-2511 = Locals Byte
251F-251F = Guide Byte
2540-2547 = ZKT Data
2548-254F = ZKT Preamble
2550-258F = Primary ZKT Table
2590-25CF = Second ZKT Table
25D0-260F = Third ZKT Table
2610-264F = Fourth ZKT Table
2658-265F = EEPROM Decrypt Key 2
2EEC-2EF7 = USW 12 Byte Write Key
2EF7-3FFF = Code & Data ?

That's the EEprom. We can modify this area

Now the ROM.

Addressed @ C000-FFFF and cannot be modified.

Rom contains static routines/programs that are called from various locations
in the
EEprom. A disassembled ROM dump of a 6B card is located in the
HU-Documentation.zip file. You will need this !!

--------------------------------------------------------------------------------

More on opcodes & registers..

We have 2 registers commonly used for calculations and temporary storing of
data. Reg A & B

MOV #00, A - Sets A to Zero
INC A - Adds 1 to A
DEC A - Subtracts 1 from A
XOR #01, A - 01 xor 00 = 01
MOV A, B - A --> B
CLR A - Zero out A
INC B - Add 1 to B

Note: (Oprand1)--->(Oprand2)
MOV A,B (B) receives the value of (A)


Lets look at MOVE and its variations.. Page 555 in spnu527a shows the move
statement. Don't get overwhelmed with all the variations, focus on the ones
most
commonly used.

MOV Move
Syntax: MOV s,d
Execution: (s) -->(d)

The value in oprand (s) source is copied into (d) the destination. The
original
value is still left in (s). The values is actually copied not moved.

Example:

C0 MOV A,B (A) -->(B)

It this statement, the opcode is C0. It requires 1 byte and it copies the
value
of register A into Register B. Using the opcode C0 implies the oprands A,B.
If you use an assembler to help you code, you don't need to remember all of
the
HEX opcodes, the assembler will convert to the proper opcode based on the
syntax
of the instruction you use. Below is some examples of variations of the MOV
instruction.

MOV R32,R105 Move the contents of register 32 to register 105

MOV #010h,R3 Move #010h to register 3

MOV A,*2Fh[R32] Move the contents of register A to the location
002Fh+(R31:R32)

MOV LABEL,A Move the contents of the location at LABEL to register A

Note: using an assembler allows you to use labels or symbolic names to
represent memory locations.

A good 370 assembler is provided in
http://www.dssftp.com/Docs/hu-documentation.zip

--------------------------------------------------------------------------------

The Stack:
The stack is a LIFO buffer. Last in - First out. The stack
can be thought of as a stack of plates. You put one on the top, then
another,
then another. If you want the 1st plate you put on the stack, you must
remove
the last 2 you placed there.

The stack is also used to temporarily store values.

To place a value on the stack use push.

PUSH A
PUSH B
PUSH 5E

To remove a value use POP

POP 5E
POP B
POP A

Note that we must pop values off the stack in the opposite order in which we
pushed the values. This maintains continuity using a LIFO buffer.

Other registers of note are:

SP - Stack pointer: It will contain the current address off the stack.

ST - Status register: Bits will change in this register based on a
calculation,
comparison or some other operation.

PC - Program counter: The address of the current instruction/opcode being
executed. (This value is maintained automatically and should not be changed
manually)

--------------------------------------------------------------------------------

Lets look at some real code..This is a subroutine and would normally be
called
by a statement such as..

2350 8E 23 69 Call 2369 - Begin subroutine at 2369;
2353 FF nop <-- Returns to the location just after the call when a
RTS
is encountered

Note: this is actually achieved by pushing the PC+2 onto the stack and the
RET
actually pops it off so program flow continues at 2353. The call pushes the
PC
and the return pops the PC.

2369 : C5 clr B - Zero B
236A : AA 2A F8 mov *2AF8+B,A - copy data to A
236D : D0 24 mov A,24H - Move date to 24H
236F : AA 3F 50 mov *3F50+B,A - Copy more data to A
2372 : 13 24 xor 24H,A - XOR data into A
2374 : 8E 3C 96 call #3C96 - Call routine to send data to asic
2377 : C3 inc B - add 1 to B
2378 : 5D 08 cmp #08,B - Compare b to #08h
237A : 0F EE jlt 236A - loop and get more date til B=8
237C : F9 rts - Return from subroutine


As you can see, it's all about the same 4 operations I discussed at the
onset.

1) Moving data from one place to another
2) Performing some type of mathematical operation
3) Comparing
4) Branching

A lot can be done with these simple concepts and I hope this will inspire
you to
dig a little deeper and learn more about what's really happening on the
cards
themselves.


PART #2
Back to Top


Addressing Modes:

These are the types of addressing modes available. Don't worry, they are not
as
complicated as they look.

Implied
Direct
Register
Indexed
Peripheral
Indirect
Immediate
Offset Indirect
Stack pointer relative

The direct, indexed, indirect, and offset indirect addressing
modes always use Register A as the operand to generate a 16-bit address.
These addressing modes are used only by the compare (CMP) and move
(MOV) instructions.

Here are examples of each of the addressing modes:

--------------------------------------------------------------------------------

MOV #01Ch,B ; Immediate

The # preceding the 1Ch tells us the actual value 1Ch is to be stored in B.

Other examples:
---------------
AND #FEh,R05 - FEh and (R05) --> (R05)
ADD #23h,R07 - 23h + (R07) --> (R07)

--------------------------------------------------------------------------------

LDSP ; Implied

In this case we have implied operands. Load the stack pointer with the value
in
B. Can be thought of as MOV B, SP

You do not have to specify the operands, because they
are inherently specified in the instruction.

--------------------------------------------------------------------------------

MOV *06h[SP],A ; Stack Pointer Relative

This statement directs the CPU to store a value in A relative to the stack
pointer. The value at (SP+06H) is stored in A.

--------------------------------------------------------------------------------

MOV &2345h,B ; Direct

Here we are using a 16 Bit address directly. The "&" preceding the address
directs the CPU to place the value located at (2345h) into (B).

MOV &2014,A - (2014h) --> (A) - Value @ 2014 stored in A
MOV A,&1234h -(A) --> (1234h) - Value in A stored at 1234h

--------------------------------------------------------------------------------

MOV *R04,A ; Indirect

Indirect addressing simply means that we will be pointing to an address
rather than a value. We will use that address to fetch/store the value.
The above statement directs the CPU to use the address located at register
pair
(R03:R04) and move the value at that address into A

For example.

R04 has a value of FFh
R03 has a value of 20h

The value located at (20FFh) is moved into (A), not the value located at R04
witch is FFh. That would be written as MOV R04, A without the preceding "*".

In indirect addressing modes, instructions use the contents of a register
pair
as the 16-bit address of the data.

--------------------------------------------------------------------------------

MOV R05,R08 ; Register

Here we are just moving the value contained in one register to
another The value in (R05) --> (R08)

--------------------------------------------------------------------------------

MOV *3456h[B],A ; Indexed

The indexed addressing mode generates a 16-bit address by adding the
un-signed
contents of register B to a 16-bit unsigned constant. It your example
suppose
register B contains the value 5.

Then the value at (3456h + 05h) will be stored in A. Register B acts as an
index
or offset.

--------------------------------------------------------------------------------

MOV *04h[R08],A ; Offset Indirect

Which brings us to offset indirect. This is basically the same as Indirect
address mode with an offset.

Example:

R07 contains the value C0h
R08 contains the value FFh

So being this is Indirect, we use the address stored at reg pair (R07:R08)

So the value at location ((C0FFh) + 04h) is stored in (A)

The offset indirect addressing mode generates a 16-bit address by adding an
8-bit signed offset to an address taken from a register pair. Offset
indirect
addressing is useful for stepping through tables.

--------------------------------------------------------------------------------

MOV R08,P020 ; Peripheral

The peripheral addressing mode is used for program control of the peripheral
on-chip modules such as timers, interrupts, and I/O ports. Devices with bus
expansion can address a small amount of external memory as peripheral file
(PF) space. This begins at 1000h so P020 refers to the address 1020h

In the example above, the value at (R08) is stored into (P020).

Other examples:
===============
MOV P025, A - (P025) --> (A)
MOV B, P022 - (B) --> (P022)

--------------------------------------------------------------------------------

Note: These addressing modes are used in data manipulation, Comparisons and
Branching statements.



PART #3

Back to Top

Registers & Traps
----------------------------
Status Register - (more details)

Most of the instructions affect the bits in the status register.
Depending on the result of the operations, the bits will be set or cleared.

Refer to Page 116 in SPNU for more detail.

8 bit status register:
-------------------
7 6 5 4 3 2 1 0
C N Z V E1 E2 - -

C = Carry
N = Negative
Z = Zero
V = Overflow
IE2 = Level 2 interrupt enable
IE1 = Level 1 interrupt enable

Based on the results of operations one or more of the bits may be set. IE1 & IE2 will
be set if an interrupt is requested.

Note: The status register can be loaded with an Immediate value
LDST #iop8 - (iop8 --> ST)

--------------------------------------------------------------------------------


Register File (RAM) - page 123-SPNU
-----------------------------------------
A register file that can be accessed as general-purpose registers,
data memory storage, program instructions, or part of the stack

256 bytes beginning at 0000h-00FFh

The first 2 locations 0000h & 0001h are registers A & B

--------------------------------------------------------------------------------

Peripheral File: - Page 123-124-SPNU
----------------------------------------
A peripheral file that provides access to all internal peripheral mod-ules,
system-wide control functions, and EEPROM/EPROM program-ming
control. The PF includes 256 addresses in the memory map from 1000h-10FFh.

Trap Vectors: Page 576 - SPNU
==============================
Trap is a 1-byte subroutine call. The operand <#n> is a trap number that identifies a location in the trap vector table (addresses 07FC0h to 07FDFh in
memory). The contents of the 2-byte vector location form a 16-bit trap vector
to which a subroutine call is performed. When you invoke the same routine
more than once, TRAP is a more efficient instruction than CALL because fewer
bytes are needed.
Usage:
--------
TRAP #n

(SP) + 1 --> (SP) - Program counter pushed on the stack
(PC MSbyte) --> ((SP))
(SP) + 1 --> (SP)
(PC LSbyte) --> ((SP))
(Entry vector) --> (PC) - The entry point to the trap placed in PC

n = 0-15 = trap number
Trap to subroutine
Push PCN
Trap 0 = EF, Trap 15 = E0
--------------------------
It seems these traps serve a specific function on the HU.

TRAP 00 - EF ; Decrypt a byte from EEPROM To A (Eeprom address: R2FH:R30H, Destination: A)
TRAP 01 - EE ; Decrypt A byte from ram (Source: 30h, Destination: A)
TRAP 02 - ED ; Eeprom Encrypt & Write (Ram Source: R2FH:R30H, Eeprom Destination: R31H:R32H, Lenth: 06H)
TRAP 03 - EC ; RamDecrypt & Write to EEprom (Source: R2FH:R30H, Destination: R29H:R2AH, Length: 06H)
TRAP 04 - EB ; Eeprom Encrypt/Decrypt To Ram (Ram Source: R2FH:R30H, Ram Destination: R31H:R32H, Length: 06H)
TRAP 05 - EA ; Encrypt and Write 1 byte to EEPROM (Source: A Eeprom address: R2FH:R30H)
TRAP 06 - E9 ; Ram Encrypt/Decrypt A (1 byte) (Source A, destination *30h/A)
TRAP 07 - E8 ; Trap 07 Vector (Decrypted With Rom Key 72)
TRAP 08 - E7 ; Write To EEprom (8 Bit RAM Source: 15H, Destination: R29H:R2AH, Lenth 04H)
TRAP 09 - E6 ; Error Handler (Error Level: A)
TRAP 10 - E5 ; Check/Create Signature
TRAP 11 - E4 ; Decrypt/Encrypt
TRAP 12 - E3 ; Tier/PPV LooK Up (Looks for Tier or PPV Event in Tier or PPV Area)
TRAP 13 - E2 ; Receive Byte to A
TRAP 14 - E1 ; Send Byte in A
TRAP 15 - E0 ; Trap 15 Vector (Decrypted With Rom Key 72)
We need to find out more about 15 ??

Remember that we can't just use a command like
MOV A,#2024

2024 is in EEprom, not ram. So we need to use Trap 5 to write a byte to EEProm
from (A) using the address in register pair (R2FH:R30H).

Mov #24, R30h - Load LSB into R30h
Mov #20, R2Fh - Load MSB into R2Fh
Mov #FFh, A - Load byte to be written in A
Trap 5 - Write the byte

This above code would write the byte to EEprom. Notice how some writes are encrypted while others are not. Also, you may have 1,4 or 6 byte writes.

--------------------------------------------------------------------------------

Here is Trap 8 disassembled - Just FYI
----------------------------------------------------------------------------------------
E65C : 42 15 0A mov 15H,0AH ; Begin Trap 8 - EEProm Write
E65F : 42 04 0C mov 04H,0CH ; source=15H, count=04H dest=2AH
E662 : 98 2A 36 movw [2AH],36H ; save 15H->0AH,2AH->36H,04H->0CH
E665 : 42 0A 15 mov 0AH,15H ; reset 15H (from saved values)
E668 : 42 0C 04 mov 0CH,04H ; reset 04H
E66B : 98 36 2A movw [36H],2AH ; reset 2AH
E66E : 8E E6 A8 call #E6A8 ; go to the ee write routine
E671 : 42 0A 15 mov 0AH,15H ; reset 15H
E674 : 42 0C 04 mov 0CH,04H ; reset 04H
E677 : 98 36 2A movw [36H],2AH ; reset 2AH
E67A : 8E E7 77 call #E777 ; go to the verify routine
E67D : 03 02 jpz E681 ; if 00 then write passed (exit)
E67F : 00 E4 jr E665 ; else write failed (repeat)
E681 : F9 ret ; return

--------------------------------------------------------------------------------

Now to look at specific instructions in more detail..


=======
Mov s,d - Move
=======
C0 - Mov A,B - (A -->B) Simplest from of move (requires only 1 byte)
62 - Mov B.A - (B -->A) Operands are implied
D0 - Mov A, Rd (A -->Rd) - Requires 2 bytes (opcode & register)
D1 - Mov B, Rd (B -->Rd) - Register is specified - (A or B implied by opcode)

A MOV instruction that uses register A or B as an operand requires fewer
bytes.

MOV transfers values between the memory locations/registers. Immediate values can be loaded directly into the registers.

When using direct, indirect, indexed, offset indirect, and stack pointer relative addressing modes, the processor must use register A.

Some MOV instructions will effect the status register.

Note: When the MOV Pn,Rn and MOV Rn,Pn instructions are used their operands are reversed.


============
MOVW s,Rpd - Move Word
============
MOVW moves a 2-byte value to the register pair indicated by the destination
register number.
98 - MOVW Rps,Rpd - (Rps-1:Rps) -->(Rpd-1:Rpd)
88 - MOVW #iop16,Rpd - #iop16 -->(Rpd-1:Rpd)


========
CMP s,d - Compare
=======
(d) - (s) is computed but not stored. Status bits are set based on the results.
CMP compares the destination operand to the source operand and sets the
status bits in the status register.

The CMP instruction is usually used in conjunction with a jump instruction.

On the status register..

C is set if (d) >(s)
N set if (d-s) is negative
Z is set (d) = (s)
V is set if (d-s) results in an overflow

6D - CMP B,A - Requires 1 byte (operands implied)

1D - CMP Rs,A - Requires 2 bytes - (compares Reg to A)
3D - CMP Rs,B - Requires 2 bytes - (compares Reg to B)

2D - CMP #iop8, A - (Compares immediate value to A)
5D - CMP #iop8, B - (Compares immediate value to B)


====
Jcnd #off8 - Jump on Condition
====
If the tested condition is true then #off8 will be added to the program counter and program execution will resume there. PCN+off8 -->(PC). This is known as a relative jump.

The operand address must therefore be within -128 to +127 bytes of the
location of the instruction following the JMP instruction. This allows you to jump forward or backward. For longer jumps, you can use the BR (branch) or the JMPL instruction.

The Jcnd instructions are commonly used after a CMP instruction to branch according to the values tested.

02 - JEQ #off8 - Jump if equal (same as JZ)
06 - JNE #off8 - Jump if not equal

09 - JL #off8 - Jump Less than
0A - JNL #off8 - Jump Not less than
0D - JG #off8 - Jump greater than
0E - JNG #off8 - Jump Not greater than

See more on Table 16-6 - page 549.

The Jcnd does not always require a CMP instruction. Just an instruction that sets the status bits. For example..

After MOV operations, a JZ or JNZ can be used to test whether the value
moved was equal to zero. JN and JPZ are used to test the sign bit of the value moved.

In addition, the program can check the overflow bit V after executing an arithmetic instruction with the JV or JNV instructions.

00 JMP #off8 - JMP jumps unconditionally to the address specified in the operand.


===========
JMPL #off16 - Jump long
===========
This instruction works basically the same was but uses a 16bit offset.
PCN + #off16 -->(PC)


===========
BR #XADDR - Branch
===========
XADDR -->(PC) - Xaddr is loaded into the program counter.

8C - BR #iop16 - Jumps to the specified 16 bit address.
9C - BR *Rp - Jumps to the specified 16 bit address contained in Regsiter pair.

BR branches to any location in memory, including the on-chip RAM. BR supports
the following four program flow absolute addressing modes:

Direct
Indirect
Indexed
Offset Indirect

Note: Additionally, an indexed branch instruction of the form BR *TABLE[B] is
an efficient way to execute one of several actions on the basis of a control input this is similar to the Pascal CASE statement. The program can branch to
up to 128 different jump statements.

(I'm sure we all remember the CASE statement - I loved Turbo Pascal !!)

case
a=1 goto loc1
a=2 goto loc2
a=3 goto loc3
end case

Another common statement we will be seeing is the bit test and jump.
==============
BTJO s1,s2,off8 - Bit Test and Jump if One
==============
If (s1) AND (s2) <> 0, then the off8 is added to the program counter.

Example:
2040: 7640B507 btjo #40h,0B5h,204Bh

if bit 5 of B5h is set then the jump will occur.

==============
BTJZ s1,s2,off8 - Bit Test and Jump if Zero
==============
If (s1) AND NOT (s2) <> 0, then the off8 is added to the program counter.

Example:
2040: 7740B507 btjz #40h,0B5h,204Bh

if bit 5 of B5h is not set then the jump will occur.

It is beyond the scope of this tutorial to look at every instruction in detail, but this should give you the background to look at each instruction and understand what it is doing. I urge you to look over the instruction set on page 519 of the SPNU. You should take a look at the following commonly used instructions on the HU cards.
ADD
AND * important
CALL
DEC
DIV
DJNZ - * important
INC
JBIT1
JBIT0
MPY
OR - * important
POP - * inportant
PUSH- * important
RL -
RTC
RR
SUB
SWAP
XOR -* important


Exercises

Back to Top

By now you should be ready to write a few simple routines.
=======
Exercises
=======
1) Write a tms370 routine to XOR the 1st 8 bytes starting at 2CE0.
Store the results in the PPV area at 2024.

2) Write a tms370 routine to move the 1st 8 bytes at 2CE0 to
RAM(register file - locations 0001-00FF) - starting at 0009.

Next we will look at 3M code and hashes. Are we having fun yet ?

Part #4

Back to Top

Now comes the fun part!!


--------------------------------------------------------------------------------

By now you should have a basic understanding of how the tms370 CPU functions and
how to code some simple routines. Most of the routines on the HU are fairly
simple, the exception being some of the hash routines and the encryption
routines. To gain a better understanding of assembly language programming, you
need to code and trace others code. You should play around and try a few
routines on your own and try to develop your coding skills. A lot of your
initial work however will be tracing dave's code to determine exactly what's
happening. You must know exactly what's going on to be able to defeat the
hashes.

One very important thing we need to understand is the differences between the
opcodes as defined in the SPNU document and the opcode's actual function of the
HU card. There are many opcodes that are the same, but there are some important
differences are well. You need to take a close look at the
HU-Opcode-Quik-Ref.txt document located in the HU-Documentation.zip file. Print
this out and place it in your folder as it will be a most valuable tool in all
of your coding and tracing efforts.


Dynamic code and cmd82s
======================

Dynamic Code: tms370 instructions sent down via the datastream that are
executed on the fly.

Dynamic code can be anything at anytime and dave uses DC as an ECM (electronic
counter measure) to foil hacking attempts. Just after the HU unlooping software
was made public, dave began to rotate all previous ECMs at random time intervals
making the current methods of 3Ming the cards obsolete. At the time of this
document's creation, the total number of ECMs in rotation number is over 200.


How do we know what the current ECM's are and how they operate ?
=====================================================
You will need to log the data stream yourself or try to find a current listing
of all ECMs. I've posted a link to a current log of the datastream. A real time
log can be found at.

#dss-livestream at irc://irc.satirc.mine.nu

A list of current ECMs can be found at (see connected post)

=======
CMD82
=======
Dynamic code is sent via the datastream via a data packet. An example of the
packet is below..

> 48 40 20 00 58 < 40
> 7F 11 A6 6E CD CB 56 BA 5F 39 51 62 49 90 D0 CA
FA D6 11 7E 10 D6 E0 FC 25 DD B4 1E EF 28 36 2B
24 B8 7D 06 30 09 30 10 00 01 7D 14 09 15 02 49
82 14 00 06 42 FF FC F4 EA 00 2A B9 F4 CA 41 C1 <--cmd82
99 F4 06 2F 2C F9 06 83 1D 7D 17 01 8F 00 01 26
01 8F 0C 35 0E FD FA 9C
< 90 20

The packet header contains a 48 followed by INS40. The parameters passed to the
INS40 are 20 00 and the length of the data is 58h bytes. The card responds with
<40. The data is then sent and the card responds with < 90 20, received and
confirmed.

We need to look for a cmd82 within the packet and it's easily identified

82 14 00 06 42 FF FC F4 EA 00 2A B9 F4 CA 41 C1
99 F4 06 2F 2C F9

Lets take a closer look..

82 is the command
14 is the length in hex of the cmd82
00 06 is the current DSW to use
42 is the key to be used
FF FC is the range to be hashed
F4 ...F9 is the actual dynamic code to be executed.

Just disassemble the code from F4..F9 to find out what the hash is doing.

** One important item that needs to be discussed here is the ranges to be
hashed. These can be determined from the table listed below and you will see
how all of this fits together by studying the DSW6 code at 0100h.

2D4C: dw 22F2h,008Bh ; If Bit 07 of DDh(2nd byte after DSW value) is
set, hash 008Bh bytes starting at 22F2h
2D50: dw 23D5h,0031h ; If Bit 06 of DDh(2nd byte after DSW value) is
set, hash 0031h bytes starting at 23D5h
2D54: dw 2698h,007Ah ; If Bit 05 of DDh(2nd byte after DSW value) is
set, hash 007Ah bytes starting at 2698h
2D58: dw 2711h,03BDh ; If Bit 04 of DDh(2nd byte after DSW value) is
set, hash 03BDh bytes starting at 2711h
2D5C: dw 2CD0h,0010h ; If Bit 03 of DDh(2nd byte after DSW value) is
set, hash 0010h bytes starting at 2CD0h
2D60: dw 2CE8h,0064h ; If Bit 02 of DDh(2nd byte after DSW value) is
set, hash 0064h bytes starting at 2CE8h
2D64: dw 2D4Ch,0040h ; If Bit 01 of DDh(2nd byte after DSW value) is
set, hash 0040h bytes starting at 2D4Ch
2D68: dw 2D8Ch,002Bh ; If Bit 00 of DDh(2nd byte after DSW value) is
set, hash 002Bh bytes starting at 2D80h
2D6C: dw 2F08h,0132h ; If Bit 07 of DEh(3rd byte after DSW value) is
set, hash 0132h bytes starting at 2F08h
2D70: dw 3039h,011Eh ; If Bit 06 of DEh(3rd byte after DSW value) is
set, hash 011Eh bytes starting at 3039h
2D74: dw 3159h,07E1h ; If Bit 05 of DEh(3rd byte after DSW value) is
set, hash 07E1h bytes starting at 3159h
2D78: dw 393Dh,060Bh ; If Bit 04 of DEh(3rd byte after DSW value) is
set, hash 060Bh bytes starting at 393Dh
2D7C: dw 3F58h,0010h ; If Bit 03 of DEh(3rd byte after DSW value) is
set, hash 0010h bytes starting at 3F58h
2D80: dw 3F88h,0077h ; If Bit 02 of DEh(3rd byte after DSW value) is
set, hash 0077h bytes starting at 3F88h
2D84: dw 3FFFh,0001h ; If Bit 01 of DEh(3rd byte after DSW value) is
set, do nothing (unused range)
2D88: dw 3FFFh,0001h ; If Bit 00 of DEh(3rd byte after DSW value) is
set, do nothing (unused range)

Example 1: 00 10 hash range

7654 3210 <-bit
(DD:DE)=0010h therefore (DD)=00h =>0000 0000 (all bits are clear - no eeprom
hash)
(DE)=10h =>0001 0000 (only bit#4 is set - 393Dh,060Bh <=see lookup table)

Since only bit#4 of (DEh) is set or 1, the starting eeprom addy to be hashed
is 393Dh and 060Bh total bytes to be hashed.


Example 2: EF 0C hash range
7654 3210 <-bit
(DD:DE)=EF0Ch therefore (DD)=EFh =>1110 1111 (all bits are set, except
bit#4, this means all the eeprom addy
listed in the top half of the table will be hashed except the 2711h,03BDh as
bit#4 is not set)
(DE)=0Ch =>0000 1100 (only bit#2 and 3 are set - 3F88h,0077h - 3F58h,0010h)

Don't worry this will all become clear as we learn the code at 0100h and begin
to disassemble the hashes. Again this is one for the folder !!


--------------------------------------------------------------------------------

===================
DSW6 and the 0100 code
===================

The key to understanding hashing and defeating it is the code at 0100h. Yes this
is a ram location and the DSW6 code gets copied from EEprom to ram before
execution. The dynamic code is also copied into ram and executed at location
0066h called from 0119h. Here is the disassembly of the DSW6 code.


0100: C5 clr B ; Prepare to hash EEPROM
0101: 3024C80E mov &USW,0Eh ; Get the high byte of the USW from the card
0105: 8E2F8F call DoXorR14WithEEPROMKey_ ; Decrypt it with the EEPROM key
0108: B0 tst A ; ?? Don't know why this is here, the next cmp overrides
0109: 2D06 cmp #06h,A ; Cmp A (high byte of USW) with #06h
010B: F407C3A3 bnc AssertFailedAbort_; If the card is not yet at USW 0600, trap-9 and abort
010F: 32A0 mov 0A0h,B ; Get a byte of the packet hash from A0h into B
0111: 8E2CD0 call 2CD0h ; Init DBh with a random byte, clr 24h to prepare hash
0114: 8E2D8C call 2D8Ch ; Based on the last range's hash, pick a
random table entry from the table at 2D4Ch
0117: 0217 jz 0130h ; If byte count for this EEPROM block=#00h,skip the hash
0119: 8E0066 call 0066h ; Otherwise, call a dynamic function included with the INS 40 packet at 0066h
011C: 1324 xor 24h,A ; XOR that function's result with the previous byte
011E: 1BDB add 0DBh,A ; Add part of the last packet's hash
0120: D024 mov A,24h ; And store it
0122: 70012A incw #01h,29h:2Ah ; Next EEPROM address
0125: 70FF2C incw #0FFh,2Bh:2Ch ; 1 less byte
0128: 03EF jc 0119h ; If still more bytes, repeat
012A: DC24 rr 24h ; Adjust packet hash bytes
012C: DCDB rr 0DBh
012E: 00E4 jmp 0114h ; Repeat for a random number of ranges dependent on the last packet hash
0130: 1224 mov 24h,A ; Get the hashed byte
0132: 5208 mov #08h,B ; Prepare to copy 8 bytes
0134: AB00DC mov A,*00DCh(B) ; Copy it into DDh-E4h
0137: CAFB djnz B,0134h ; Repeat for 8 bytes
0139: F9 rts ; and return
013A: 275A3C96594C db 27,5A,3C,96,59,4C ; Hash initialization bytes


For reference and convenience, code from USW 0500 and 0600 is included here
since the DSW 0006 code calls it:

2CD0: 5503 and #03h,B ; Make B a number from 0-3
2CD2: AA013A mov *013Ah(B),A ; Get a hash initialization byte
2CD5: D0DB mov A,0DBh ; Put it in DBh
2CD7: D524 clr 24h ; Set up to call the routine at 2D8Ch
2CD9: 882D482E movw #2D48h,2Dh:2Eh ; With the first table entry
2CDD: D5E3 clr 0E3h
2CDF: F9 rts ; and return
2D8C: 7D08E3 cmp #08h,0E3h ; If E3h=#08h,
2D8F: 0603 jnz 2D94h
2D91: 42DEDD mov 0DEh,0DDh ; Copy DEh to DDh
2D94: 7D10E3 cmp #10h,0E3h ; If E3h=#10h, we're done, so exit
2D97: 021D jz 2DB6h
2D99: D3E3 inc 0E3h ; Otherwise increment E3h
2D9B: 70042E incw #04h,2Dh:2Eh ; Go to next table pointer
2D9E: DEDD rl 0DDh ; Shift bits in DDh
2DA0: 07EA jnc 2D8Ch ; If bit 7 of DDh was set, repeat
2DA2: C5 clr B ; Process a table entry
2DA3: 9A2E mov *2Dh:2Eh,A ; Get a byte from
*2Dh:2Eh (pointer to table entry)
2DA5: AB0029 mov A,*0029h(B) ; Put it in 29h+B
2DA8: 70012E incw #01h,2Dh:2Eh ; Advance table pointer
2DAB: C3 inc B
2DAC: 5704F4 btjz #04h,B,2DA3h ; Loop for 4 bytes EEPROM address now in 29h:2Ah, count
2DAF: 70FF2C incw #0FFh,2Bh:2Ch ; is in 2Bh:2Ch. Subtract 1 byte from count,
2DB2: 70FC2E incw #0FCh,2Dh:2Eh ; Subtract 4 bytes from table pointer
2DB5: C3 inc B ;
2DB6: F9 rts ; and exit

2D4C: 22F2 008B ; EEPROM hash range table. 1st 2 bytes are the starting
23D5 0031 ; address, next 2 bytes is the byte count for that
2698 007A ; range.
2711 03BD
2CD0 0010
2CE8 0064
2D4C 0040
2D8C 002B
2F08 0132
3039 011E
3159 07E1
393D 060B
3F58 0010
3F88 0077
3FFF 0001
3FFF 0001

Print this out and place it in your folder, trace each line of code and
ensure you understand what each line is doing. You must understand this code
above all if you want to defeat the hashes with a cloak, AI routine or table
script.

--------------------------------------------------------------------------------

===========
3M STRINGS
===========

3M strings are just a way to set the specific bits that allow viewing of a
specific channel and are normally called from within and INS54 loop or whenever
the channel is changed although can be called form other places as well.

This is a good one that will 3M the card with a ROM call and is the preferred 3M string.

3BF0 : 8E DF 51 call #DF51

Of course, this will have to be cloaked and need not be called from 3BF0. Be
creative and place your 3M in areas other than common public jumps. These
obvious jump points will be targeted more so than a private one.

Here is a another commonly used string and the jump point also needs to be cloaked

2040: 7640B507 btjo #40h,0B5h,204Bh
2044: 7203B8 mov #03h,0B8h
2047: D5B5 clr 0B5h
2049: D508 clr 08h
204B: F9 rts

2040 is checking to see if bit 6 of B5h is set. If it is it will jump over the
entire 3M and not authorize video to allow for locks and limits.
Clearing 08h, B5h and setting B8h, enables video

So as you see, the 3M string is simple. It's placing in on the card undetected..
that's the trick..


--------------------------------------------------------------------------------

==========
3M Strategy
==========

Once you understand the DSW6 code and have disassembled and looked at a few
hashes, you must decide on a strategy that will allow you to get your 3M string
on the card unhashed. The most common methods are:

1)Cloak the jump point to your 3M by intercepting the dynamic code before it
executes and feeding it the correct values for the areas of EEprom that contain
your jump points. This means that you will need to cloak two areas of the
EEprom. One for your 3M string and one for your CMD82 intercept.

2)Intercept the CMD82/Dynamic code and build a table for each hash. This
involves calculating a unique two or three byte value for each of the hashes and
storing those hash signatures in a table along with the correct values the hash
is expecting to see. This can be done by intercepting the hash, re-writing the
jump points, allowing the hash to complete, storing the results and writing back
your jump points for the intercepts. The next time you see the hash, just feed
it the correct results you have already calculated. This allows your script to
learn new hashes as they appear.

3) Tracing through the code and try to determine a unique method of 3Ming the
card. That's how the Exec/Jumpless3M and Fuse3M were discovered. This type of
info is rarely made public due to the fact that is can be worth big $$$ to the
person who discovers the methods and unless made public, will remain unhashed.

There are ways to 3M a card using these little tricks at this time and these
methods are not public and are not likely to become public unless a hobbyist
discovers it and decides to make it so.

4)The key to longevity for your 3M is to be different from the freeware releases
So be creative and most of all, have fun !!


--------------------------------------------------------------------------------

In the next installment of the HU tutorial, we will look at how to cloak in more
detail and discover some techniques to defeat large chunks of hashes with a
single, well though out routine.


I can only urge you to help others and share what you learn. Please don't use
this information for profit and remember the ideals that started this hobby.

Together we can help keep the 3M spirit alive "All for one and one for all"

Back to Top


--------------------------------------------------------------------------------