Current issue with the current system is that it is is a PLC (Programmable Logic Controller) purchased from another australian company, who purchased it from a chinese company. As with many things in the manufacturing industries, documentations is not always so forthcoming. Thus while it is operational and still useful if maintained, if things goes wrong or there is a need to improve the system. The lack of documentations will be an issue in modifying the system.

At the moment, the front user interface allows for changing the timing of the process. However the annoying thing is that the vacuum pump remain on throughout the process unnecessarily, and it is slowing down the whole process. If it can be modified to turn on only during the cooling state (where it is actually needed), the entire process can be speeded up as a result.

Be warned, this is more like a raw log rather than a teachable reference. But if you find it useful, then let me know!


Cannot be bothered arrange images, but here it is below:

Image folder


What is the specifications of the control cabin?


Human Interface Unit:
	MCGS
	MCGSTPC
	Model: TPC10K
	Input Power: 24V DC/ 300mA Max
	Interface: Serial, USB in, USB out, No LAN Avaliable

Programmable Logic Controller:
	Master-K120S
	K7M-DR60U
	"Powerful & compact block-type PLC CPU, digital I/O and power part are embedded in block-type PLCs, which is very compact and easy to install in area you want for system configuration. Also through various built-in function, user can configure cost-effective system."
	
	K120S Features:

		High-performance and various block type

		Economic type: 10/14/20/30 points (10/14 points: 2points built-in Analog Timer)
		Standard type: 20/30/40/60 points
		Various expansion modules: input, output, mixed modules
		P area extended for SMART I/O application (P000~P63F)
		High-speed processing speed: 0.1㎲/step (standard type)
		Battery-less backup
		Program backup: EEPROM backup while online editing
		Data backup: Super capacitor
		Various input handing: Input filter, pulse catch
		Enhanced communication functions

		Built-in RS-232C (Ch0) and RS-485 (Ch1) support *1)
		Transmitting data monitoring support: KGLWIN
		Various option modules
		Cnet (RS-232C, RS-422) Fnet/Rnet (master module)
		Profibus-DP/DeviceNet (slave module)
		Powerful built-in functions

		High-speed counter: 32-bit signed operation
		Counter range: -2,147,483,648 ~ 2,147,483,647
		Function: ring counter, latch counter, comparison (equal/zone/task), RPM
		Positioning function (DRT/DT type)
		Control axis: 2 axes (100kHz)
		Operation method: single, repeat
		Operation mode: end, keep, continuous
		Additional functions: return to origin, JOG operation, PWM output
		PID operation function
		Relay/PRC auto-tuning, SV ramp, delta MV, PWM output, position/velocity algorithm
		Various expansion modules

		7 Digital I/O modules: G7E-DR(08/10/20)A, G7E-TR10A, G7E-DC08A, G7E-RY(08/16)A
		9 Analog I/O modules: G7F-ADHA(B/C), G7F-AD2A(B), G7F-DA2I(V), G7F-AT2A, G7F-RD2A
		6 Comm. modules: G7L-CUEB(C), G7L-DBEA, G7L-PBEA, G7L-FUEA, G7L-RUEA
		2 Option modules: G7E-RTCA, G7M-M256B
		Specification

	Source: http://www.electmec.com/2013-01-18-15-40-35/automation/2013-01-18-16-03-42/master-k-series/k120s

So some points to consider:

  • The PLC is most likely programmed in Ladder Logic Style. (One of the specification fields said: "Program language: Mnemonic, Ladder")
  • We do not need to modify the human user interface, it seems. The critical process logic is located in the PLC I think.

Is it a mechanical/electrical issue?

By observation, it was determined that there was nothing wrong with the mechanical or electrical wirings of the device. This is since the vacuum pump was able to switch on and off at the start and end of the process (but we want it on only during parts of it), and that it is possible via the Human Interface Unit to enable one or two or both vacuum pumps. So it is a software issue.

Which means we need to modify the code within the PLC.

But how?

Generally you can program most PLCs via either Serial port, or by USB if you have a newer PLC. But that means we need to get our hands on the PLC software.

So lets look at the PLC manufactur's website download page. http://www.electmec.com/downloads/ . There is none that says exactly our model, but the KGL-WIN looks very similar. A quick google search about KGL-WIN, gets this description. (Source: http://jp.lsis.biz/product/product_detail.asp?product_code=P00148 )

Introduction

KGL-WIN is the software tool that programs and debugs for all Master-K PLC series.
Features

1) Program Compatible between LS Master-K Series.
A user can use the Program (*.PGM) created in LS Master-K Series for the Program created in other LS Master-K Series as well. The Program, Parameter or Variable/Comment created in KGL-DOS or GSIKGL can be also used in KGL for Windows.
2) PLC System Configuration by Project Structure
KGL for Windows manages the User-Defined Program as one Project including Parameter and Variable/Comment. Also a user can save a Program (*.PRG), Parameter (*.PMT), Variable (*.VAR) or Comment (*.CNT) respectively and the stored each File can be used for other Project files.
3) User Friendly Interface
Easy and useful interface for Creating, Editing and Monitoring.
4) Online Editing
A Real Time Editing is available in Online mode. The Program edited in the Online condition can be downloaded automatically without stopping PLC Hardware.
5) Monitoring the Information from PLC
A user can easily monitor PLC status such as Error Status, Network Information and System Status.
6) Debugging and Self-diagnosis (in New MASTER-K Series)
Trigger and Forced I/O Enable are available for the accurate Debugging.

So it looks like that this is the software we need to at the very least inspect the firmare of the PLC.


KGL-WIN

So attempting to download any information I can get inside the PLC, via KGL-WIN.

First I set-up a new project. It ask me for Project Property. Recall that the PLC is Master-K120S with model number K7M-DR60U :

PLC TYPE:
	MK_S
		-> 120S

I think it is MK_S --> 120S as that makes the most sense to me at at least. (As in Product brand named Master of model S of model number 120S )

Now trying to connect to it (after going to project>options , and setting up the serial port connection)

Issue: The PLC is locked with a password... could try bruteforcing the password... or try finding the source code.

Finding the password

There is two approach to finding the password. I could try sniffing the protocol between KGL-WIN and the PLC, and then create a script to basically brute force the password.

Or we could just ask for a password (and while we are at that, ask for the source code as well)

Protocol known so far for dataset3

in dataset 3, where we randomly try to guess the password, the acceptable password range is 0 to 99999999 (8 places). This means in binary (unsigned integer), the password is about ~27 binary digits (recall that the number of permutations in n places binary is `permutations = 2^n` . Thus ` n = log_2(99999999)`)...

perm = log(99999999)/log(2)
 perm  = 26.575425  
-->27/4
 ans  = 6.75  
-->27/8
 ans  = 3.375  

which we would expect the password to be around either 4 char(8bits) or 7 nibbles(4bits) long.


Patterns identified in dataset 3

Analysis of attempted communication to PLC (no known password)

Frame structure according to datasheet (chapter 8 Communication Functions)

NOTE from later on: I suspect this might not be the real structure, since KGL-WIN uses a x02 as the start header, and I think it doesn't reference station number. (Which makes sense, since you usually only program one PLC at a time). Page is updated to match my new understanding.


UNDOCUMENTED FORMAT?:
	Request Frame (-->):
		[ KGL-WIN ENQ:x02 ][ 2 byte command][command type]	[data(strct)]	[Tail (EOT)][Frame Check (BCC)]
		
	ACK Frame (<--):
		[ACK][ 2 byte command][command type]			[data(strct)]		[Tail (ETX)][Frame Check (BCC)]
	
	NAK Frame (<--):
		[ACK][ 2 byte command][command type]		[4 byte error code]		[Tail (ETX)][Frame Check (BCC)]



Base Format:
	Request Frame (-->):
		[ENQ][Station #no][command][command type]	[data(strct)]		[Tail (EOT)][Frame Check (BCC)]
		
	ACK Frame (<--):
		[ACK][Station #no][command][command type]	[data(strct)]		[Tail (ETX)][Frame Check (BCC)]
	
	NAK Frame (<--):
		[ACK][Station #no][command][command type]	[4 byte error code]	[Tail (ETX)][Frame Check (BCC)]

	CODES | HEX	 |	 NAME 			|	CONTENT
	ENQ 	x05		 Enquire 			Request frame initial code
	ACK 	x06		 Acknowledge		ACK response frame initial code
	NAK 	x15		 Not Acknowledge 	NAK response frame initial code
	EOT 	x04		 End of Text 		Request frame ending ASCII code
	ETX 	x03		 End Text Response 	frame ending ASCII code
	
	KGL-WIN ENQ : x02 :  Suspected alternative header for accessing admin/programmer controls of a PLC

Btw you can identify some of these hex codes by character:

	CODES | HEX	 |	 ASCII Character
	ENQ 	x05			`ENQ`
	ACK 	x06			`ACK`
	NAK 	x15			`NAK`
	EOT 	x04			`EOT`
	ETX 	x03			`ETX`

Possible "attempt to open connection":

My guess is yC is the command characters. And that it is asking for a password.

note: . is often a place holder for unknown or command characters.

--> Write to PLC
000070: 25.02.2015 09:51:27.197 +0.0
 02 79 43 38 38 32 43 03				.yC882C.
 
<-- Read from PLC
001809: 25.02.2015 09:51:27.197 +0.0
 06 79 43 50 41 53 53 46 33 04			.yCPASSF3.

Strangely I think for this one... ENQ is actually 02 so let's assume that for now. And station number is probbly [st#no] hex(6A) = char(j) = numerical(106)...

(On another thought. I think x02 is basically a special undocumented start frame for programming modes)

--> Write to PLC
[ KGL-WIN ENQ:x02 ][ command: x79 x43 ][?? HEX PASSWORD: 38 38 32 43 ??][ETX:0x03]
 
<-- Read from PLC
[ACK:x06][command: x79 x43 ][ "PASSF" ][EOT:0x04]

Hmmmm... "PASSF"... maybe that means password fail? Seems so, as I see the EOT is only used after "PASSF". And EOT is usually for stating the and of an ASCII text transmission.

(found how to send password later on)

What is command x43 ???????

unknown

-->
007532: 25.02.2015 09:51:27.244 +0.0
 02 72 4D 30 30 36 33 30 30 30 32 34 41 03		.rM006300024A.
 
<--
009757: 25.02.2015 09:51:27.244 +0.0
 06 72 38 31 30 31 33 43 04						.r81013C.

Doesn't match known pattern... but it does have an r char in front, which may indicates a read operation. So this is a guess

--> Write to PLC
[ KGL-WIN ENQ:x02 ][ command: x72 ][ ?? ][ETX:0x03]
 
<-- Read from PLC
[ACK:x06][ command: x72 ][ ?? ][EOT:0x04]

Heartbeat?

This one occurs in a periodic manner

-->
014002: 25.02.2015 09:51:27.306 +0.0
 02 6A 36 41 03							.j6A.
 
<--
014039: 25.02.2015 09:51:27.306 +0.0
 06 6A 34 32 33 32 30 30 38 31 30 31 30 30 30 30
 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30
 30 30 37 46 04
 
 .j42320081010000 0000000000000000 007F.
 

-->
015622: 25.02.2015 09:51:28.338 +0.0
 02 6A 36 41 03							.j6A.
 
<--
 016869: 25.02.2015 09:51:28.338 +0.0

 06 6A 34 32 33 32 30 30 38 31 30 31 30 30 30 30
 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30
 30 30 37 46 04
 
 .j42320081010000 0000000000000000 007F. 

-->
	[ KGL-WIN ENQ:x02 ][]

<--
[ACK:x06][st#no: x72 ][command: x38 ][ "PASSF" ][EOT:0x04]

What the heck is this?

assuming .XX is the format of having a 3 letter command characters (Which I found is to be semi correct... it's actually [ENQ][Station #no][command] ). I suspect .yA to be the command for the password.

1120 1120 3141 5926

-->
070536: 25.02.2015 09:51:37.919 +0.0

 02 79 41 30 31 30 32 30 33 30 34 30 35 30 36 30
 37 30 38 44 45 03
 
 .yA0102030405060
 708DE.

<-- 
072871: 25.02.2015 09:51:37.919 +0.0
 15 30 32 36 32 04						
 
 .0262.
 
-->
073280: 25.02.2015 09:51:37.934 +0.0
 02 79 44 39 39 32 46 03
 
 .yD992F.
 
<--
075351: 25.02.2015 09:51:37.934 +0.0
 06 79 37 39 04	
 
 .y79.
 

Getting somewhere?

This is getting pretty annoying.... but I think I identified the struct now:


-->
070536: 25.02.2015 09:51:37.919 +0.0
 02 79 41 30 31 30 32 30 33 30 34 30 35 30 36 30 37 30 38 44 45 03
 
.yA0102030405060708DE.

<--
072871: 25.02.2015 09:51:37.919 +0.0
 15 30 32 36 32 04
 
.0262.
 
-->
073280: 25.02.2015 09:51:37.934 +0.0
 02 79 44 39 39 32 46 03
 
.yD992F.
 
<--
075351: 25.02.2015 09:51:37.934 +0.0
 06 79 37 39 04
 
.y79.

-->
075822: 25.02.2015 09:51:39.091 +0.0
 02 79 43 38 38 32 43 03
 
.yC882C.
 
<--
078239: 25.02.2015 09:51:39.091 +0.0
 06 79 43 50 41 53 53 46 33 04
 
.yCPASSF3.
 

At some point, one of my attempted password was 12345678, so if the password was sent as a string padded with ASCII 0, then the struct might look like look like this. ( I guess they use 0 as an "escape code" so you can have variable amount of character for password. Maybe it could be a ascii passphrase too, but perhaps is artifically restricted by KGL-WIN to be between 0~99999999.)

So here are all the instances which has the initial hex code of 02 79 41 for starting the password check request. (Note: all gets HEX:15 30 32 36 32 04 ASCII:.0262. as the response)

All header frames ends with ETX because it is not a string response/request.

070536: 25.02.2015 09:51:37.919 +0.0
	-1|-2|-3|-4|-5|-6|-7|-8|-9|-A|-B|-C|-D|-E|-F|-G|-H|-I|-J|-K|-L|-M|
	02 79 41 30 31 30 32 30 33 30 34 30 35 30 36 30 37 30 38 44 45 03
	.yA0102030405060708DE.
	
	[ KGL-WIN ENQ:x02 ][  Command: x79  x41 ][ ASCII password escaped via `0`: 12345678 ][ Not sure about: x44 x45 ][ ETX: x04 ]
1557112: 25.02.2015 09:56:59.438 +0.0
	-1|-2|-3|-4|-5|-6|-7|-8|-9|-A|-B|-C|-D|-E|-F|-G|-H|-I|-J|-K|-L|-M|
	02 79 41 30 30 30 30 30 31 30 31 30 32 30 30 30 31 30 31 43 30 03
	.yA0000010102000101C0.

	[ KGL-WIN ENQ:x02 ][  Command: x79  x41 ][ ASCII password escaped via `0`: 00112011 ][ Not sure about: x43 x30 ][ ETX: x04 ]
1662740: 25.02.2015 09:58:08.756 +0.0
	-1|-2|-3|-4|-5|-6|-7|-8|-9|-A|-B|-C|-D|-E|-F|-G|-H|-I|-J|-K|-L|-M|
	02 79 41 30 39 30 39 30 32 30 30 30 39 30 39 30 32 30 30 45 32 03
	.yA0909020009090200E2.
 
	[ KGL-WIN ENQ:x02 ][  Command: x79  x41 ][ ASCII password escaped via `0`: 99209920 ][ Not sure about: x45 x32 ][ ETX: x04 ]

For the error message for password:

1666435: 25.02.2015 09:58:08.756 +0.0
	-1|-2|-3|-4|-5|-6|
	15 30 32 36 32 04
	.0262.
	
 	[ ACK ][ UNKOWN STRUCTURE:  x30 x32 x36 x32 ][ ETX: x04 ]

I suspect that responses to the password is always of the form of [ ACK ][ Status Hex to 4 places ][ ETX: x04 ], so any attempt at brute forcing, would involve testing for 15 30 32 36 32 04 response code, until it says something different (Like a success status).


Did I guess the framing wrong?

I'm starting to suspect that the framing does not include a "station number". But rather it contains only the command code. This is since the serial monitor for KGL-WIN communication to the device, seems to have a pattern of the first two characters (besides the start header) being letters.

You'll might intentionally do this, so that debugging it is easier visually in a hex monitor.

If that is the case then change:

	[ KGL-WIN ENQ:x02 ][ STATION NUM: x79 ][ Command: x41 ][ ASCII password escaped via `0`: 12345678 ][ Not sure about: x44 x45 ][ ETX: x04 ]

to

	[ KGL-WIN ENQ:x02 ][ Command: x79 x41 ][ ASCII password escaped via `0`: 12345678 ][ Not sure about: x44 x45 ][ ETX: x04 ]

Whats the commands list for the special programmer mode?

no idea, but lets just list em out anyway


[ Special Header: x02 ][ Command Byte]

Command Byte:
	Hex 	| ASCII	 : Description
	---------------------------------------
	x79		| y		 : Related to Password?
	x79 x41	| yA	 : Send a password to PLC 
	x79	x43	| yC	 : ??
	x79	x44	| yD	 : ??

	
	xA6		| j		 : Suspected Heartbeat (it is periodic)
			|| Response is probably a semi long message about the device type/name/model/stationNumber
	
	x72		| r		: no idea...
	x72 x4D | rM	:
	
	

Noticed that for passwords, the command packets tend to go yA, yD, and yC

Sometimes it also goes yD and yC only. Maybe that's when you send an empty password field.

Also noticed that the two repeated rM command occurs twice, after a heatbeat from the yA yD and yC sequence.

You can see this in this snippet


... streams of j hearbeats ...

070536: 25.02.2015 09:51:37.919 +0.0
 02 79 41 30 31 30 32 30 33 30 34 30 35 30 36 30 37 30 38 44 45 03
 .yA		0102030405060708DE.
 
073280: 25.02.2015 09:51:37.934 +0.0
 02 79 44 39 39 32 46 03 
 .yD		992F.
 
075822: 25.02.2015 09:51:39.091 +0.0
 02 79 43 38 38 32 43 03
 .yC		882C.
 
079330: 25.02.2015 09:51:39.106 +0.0
 02 6A 36 41 03
 .j			6A.
 
084390: 25.02.2015 09:51:39.137 +0.0
 02 72 4D 30 30 36 33 30 30 30 32 34 41 03
 .rM		006300024A.
 
087382: 25.02.2015 09:51:39.153 +0.0
 02 72 4D 30 30 36 33 30 30 30 32 34 41 03
 .rM		006300024A.
 
... streams of j hearbeats ...



Hmmmm.... Now the picture is getting clearer:

perhaps the serial monitor misses a few entries initially, and that asides from the initial command, most has been captured.

But I do worry that there needs to be an initial set of commands to switch to " programming mode ". I'm not quite sure what can be done about that. But an option could be to activate KGL-WIN, and then swap serial ports to a brute force script. That way, I don't need to know the initial set of commands.


So for brute forcing, you'll want to emulate the above sequence of .yA .yD .yC and .j .rM .rM before going to the next cycle of passwords to test.


078448: 25.02.2015 09:42:38.400 +0.0
 02 79 41 30 31 30 31 30 32 30 30 30 31 30 31 30 32 30 30 43 32 03
 .yA 01 01 02 00 01 01 02 00 C2.
 
 Password: 1120 1120
 Checksum?: ascii:C2 = dx194 = x43 x32 
"""

Maybe try adding it all together and taking the last few digits?:

BCC When command is lowercase(r), only one lower byte of the value resulted by adding 1 Byte each to ASCII values from ENQ to EOT is converted into ASCII and added to BCC. For example, the BCC of the above frame is gotten as below: H05+H32+H30+H72+H53+H53+H30+H31+H30+H36+H25+H4D+H57+H31+H30+H30+H04 =H03A4 Therefore BCC value is A4.



-----

H05+H32+H30+H72+H53+H53+H30+H31+H30+H36+H25+H4D+H57+H31+H30+H30+H04 =H03A4


Was trying to generate BCC via this script in python3.x :

import binascii

hexarray = [] binarray = []

while 1: hexnumber = input('> ') if hexnumber == 'q': break hexarray.append(hexnumber) binarray.append(binascii.unhexlify(hexnumber))

See if we can replicate the ??Checksum?? in here

print("add hex test") binsum = b'\x00' for x in binarray: # below doen't work as it treats it like concatnating a string # binsum += x # try this instead summing = int.from_bytes(binsum, byteorder='big') + int.from_bytes(x, byteorder='big') binsum = summing.to_bytes(4, byteorder='big')

print(">>summation: "+str(binsum)) print(">>BCC: "+str(binsum[2:4]))


05 32 30 72 53 53 30 31 30 36 25 4D 57 31 30 30 04 q add hex test

summation: b'\x00\x00\x03\xa4' BCC: b'\x03\xa4'


Seems to match up at least for BCC (but that's mostly for normal situation, not sure for the password frame however)

---

unfortunately... this doesn't match how the last 2 bytes in the password entry frame works... specifically the **43 33** part of "02 79 41 30 33 30 31 30 34 30 31 30 30 30 30 30 30 30 30 **43 33** 03". I still suspect it is some sort of checksum


908450: 25.02.2015 09:46:42.607 +0.0 02 79 41 30 33 30 31 30 34 30 31 30 30 30 30 30 30 30 30 43 33 03 .yA0301040100000000C3.


Well, until I can work that last bit out. I might as well wait for the new passwords. But hopefully this may help others who need to work out how to retrieve the password, with at least a starting point.