Tutorial:Odysseus Bundles

From The iPhone Wiki
Revision as of 06:37, 24 April 2017 by Haniag (talk | contribs) (This tutorial is for creating an Odysseus bundle for iPhone5,1 9.3.3)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Odysseus is a tool to upgrade/downgrade 32-bit devices to an unsigned iOS version as long as the device has valid SHSH blobs for it. The tool was originally created by xerub.

In order for Odysseus to work, it needs bundles for the intended firmware. These bundles are composed of 4 files; 3 patches and 1 plist. The patch files contain patches to ASR, iBEC and iBSS to ensure that iDevice boots up while skipping certain verifications to ensure that unsigned firmware can be installed.

To be able to create the patches, one needs several files from related IPSW. In this tutorial, we will be using the iPhone5,1 9.3.3 IPSW.

After running this tutorial and creating the iPhone5,1 9.3.3 bundle, you can use the same logic to create other bundles as code will be similar.

WARNING: This tutorial is for advanced users. You are proceeding on your own risk, as patching something incorrectly will result in unintended consequences in addition to restoring to currently singed un-jailbroken firmware.

Getting Decrypted Files

1) Download the iPhone5,1 9.3.3 IPSW. Alternatively, you can use partial zip to grab the files below

2) Change the extension from IPSW to ZIP, and grab the following files:

  • 058-49199-034.dmg (Restore Ramdisk)
  • kernelcache.release.n41
  • Firmware/dfu/iBEC.n41.RELEASE.dfu
  • Firmware/dfu/iBSS.n41.RELEASE.dfu

3) Decrypt the files using Firmware Keys and xpwntool

For all files except kernel: xpwntool [file in] [file out] -k [key] -iv [key]

For kernel, there are a couple of ways, but you can use:

img3decrypt.rb kernelcache.release.n41 [key] [iv] kernelcache.decrypted
lzssdec -o 384 < kernelcache.decrypted > kernelcache.decrypted.arm

Kernel Disassembly

We need to disassemble kernel in order to retreive offsets that we will use when patching iBEC. Load the final decrypted kernel file (kernelcache.decrypted.arm) using IDA, select "ARM Little Endian" under "Processor Type" and let it do its thing. When done, we will be looking for 2 offsets:

  • First Offset

1) In IDA's right panel, search for "entitlements are not a dictionary". This will be in the "com.apple.driver.AppleMobileFileIntegrity" section
2) Double click "loc_80775D12" right before the text we searched for
3) Double click "sub_80776B2C", which is the 2nd BL in the instruction
4) This will take you to an instruction similar to this:

com.apple.driver.AppleMobileFileIntegrity:__text:80776B2C sub_80776B2C                    ; CODE XREF: sub_80775C88+9Ap
com.apple.driver.AppleMobileFileIntegrity:__text:80776B2C                                 ; sub_80777068+44p
com.apple.driver.AppleMobileFileIntegrity:__text:80776B2C
com.apple.driver.AppleMobileFileIntegrity:__text:80776B2C var_10          = -0x10
com.apple.driver.AppleMobileFileIntegrity:__text:80776B2C
com.apple.driver.AppleMobileFileIntegrity:__text:80776B2C               PUSH            {R4-R7,LR}
com.apple.driver.AppleMobileFileIntegrity:__text:80776B2E               ADD             R7, SP, #0xC
com.apple.driver.AppleMobileFileIntegrity:__text:80776B30               STR.W           R8, [SP,#0xC+var_10]!
com.apple.driver.AppleMobileFileIntegrity:__text:80776B34               MOV             R4, R0
com.apple.driver.AppleMobileFileIntegrity:__text:80776B36               LDR             R0, =(unk_80779E70 - 0x80776B44)
com.apple.driver.AppleMobileFileIntegrity:__text:80776B38               MOVS            R6, #1
com.apple.driver.AppleMobileFileIntegrity:__text:80776B3A               LDRB.W          R1, [R4],#1
com.apple.driver.AppleMobileFileIntegrity:__text:80776B3E               LDR             R2, =(unk_8077A270 - 0x80776B4E)
com.apple.driver.AppleMobileFileIntegrity:__text:80776B40               ADD             R0, PC ; unk_80779E70
com.apple.driver.AppleMobileFileIntegrity:__text:80776B42               ADD.W           R3, R0, R1,LSL#2
com.apple.driver.AppleMobileFileIntegrity:__text:80776B46               LDRH.W          R8, [R0,R1,LSL#2]
com.apple.driver.AppleMobileFileIntegrity:__text:80776B4A               ADD             R2, PC ; unk_8077A270
com.apple.driver.AppleMobileFileIntegrity:__text:80776B4C               MOVS            R0, #0x13
com.apple.driver.AppleMobileFileIntegrity:__text:80776B4E               LDRH            R3, [R3,#2]
com.apple.driver.AppleMobileFileIntegrity:__text:80776B50               MLA.W           R5, R3, R0, R2

5) Record the offset for this sub, where in IDA it will show in bottom left of the right panel. Here, it will be "0x72CB2C".

This offset is needed to patch AppleMobileFileIntegrity.

  • Second Offset

1) In IDA's right panel, search for "com.apple.security.sandbox:__text"
2) If you don't see disassembled code (like above), then you need to convert to arm thumb mode. Press "cmd+G" when using mac, enter for "Value" "0x1" and press "Ok". You will then see disassembled code
3) Continue search for "mac_label_get"
4) Double click "sub_80EA3F70" for "mac_label_get" (the sub is found to the right of it)
5) Double click "sub_80E96C58", which is a reference for that previous "sub_80EA3F70" (to the top after CODE XREF)
6) This will take you to an instruction similar to this:

com.apple.security.sandbox:__text:80E4B270 loc_80E96C60     		; CODE XREF: sub_80E96C58+2j
com.apple.security.sandbox:__text:80E4B270                      	; sub_80E971E4+14p ...
com.apple.security.sandbox:__text:80E96C60                 PUSH            {R4,R7,LR}
com.apple.security.sandbox:__text:80E96C62                 ADD             R7, SP, #0xC+var_8
com.apple.security.sandbox:__text:80E96C64                 MOV             R4, R0
com.apple.security.sandbox:__text:80E96C66                 CMP             R4, #0
com.apple.security.sandbox:__text:80E96C68                 BEQ             loc_80E96CA6
com.apple.security.sandbox:__text:80E96C6A                 LDR             R0, =(unk_80F14FE4 - 0x80E96C70)
com.apple.security.sandbox:__text:80E96C6C                 ADD             R0, PC ; unk_80F14FE4
com.apple.security.sandbox:__text:80E96C6E                 BL              sub_80EA3F40
com.apple.security.sandbox:__text:80E96C72                 LDR             R0, =(dword_80F14FF0 - 0x80E96C78)
com.apple.security.sandbox:__text:80E96C74                 ADD             R0, PC ; dword_80F14FF0
com.apple.security.sandbox:__text:80E96C76                 LDR             R1, [R0]
com.apple.security.sandbox:__text:80E96C78                 MOV             R0, R4
com.apple.security.sandbox:__text:80E96C7A                 BL              sub_80EA3F70
com.apple.security.sandbox:__text:80E96C7E                 MOV             R4, R0
com.apple.security.sandbox:__text:80E96C80                 CBZ             R4, loc_80E96C9C
com.apple.security.sandbox:__text:80E96C82                 ADD.W           R0, R4, #0x64
com.apple.security.sandbox:__text:80E96C86                 DMB.W           ISHST

7) Look for offset in IDA at "BL sub_80EA3F70". Here, it will be "0xE4CC7A".

This offset is needed to patch Sandbox, which goes together with first offset.

ASR Patch

  • Grab the ASR file after mounting the decrypted Restore ramdisk found in "usr/sbin/" and load in IDA as above.
  • In IDA's right panel, search for "failed signature"
  • Calculate the value needed to do a branch from failed instruction to passed instruction (which should be before or after it). In this case, it will be from "176E4" to "1768C", which will be D2 E7
  • Apply patch by clicking in signtuare failed line, then by going in IDA to Edit->Patch Program->Change Byte, and replace the first bytes with D2 E7. Then Edit->Patch Program->Apply patches to input file, and check box for create a backup. You will notice the branch visually pointing from signtaure failed (text no longer visible) to signature passed
  • Run "ldid -s" on patched file
  • Create a .patch file by diffing both files: bsdiff [original] [patched] asr.patch
  • Alternatively, you can use this ASR patcher by /u/gjest to automatically patch ASR and produce a .patch file. The tool is currently in Beta.

Patching ASR (Apple System Restore) will enable us to skip verification of whether the rootfs had any modifications to it or not.

iBEC Patch

1) We first need to locate a code cave to add new code to it. Afterwards, we need to add new code that will utilize the offsets that we found in kernel to patch them. The code cave for iBEC is typically in 1A8 location.

  • Load decrypted iBEC in IDA, and right panel, search for "0xFEEDFACE" and record its offset that will be "1A7AC". Calculate a branch from "1B4" (will show you why later) to that offset. This will be 1A F0 FA BA
  • Update the kernel offsets we found earlier to arm thumb:

0x72CB2C = 0072 CB2C = 2CCB 7200
0xE4CC7A = 00E4 CC7A = 7ACC E400

  • Open a program to edit hex like "Hex Fiend", and open decrypted iBEC. Click on left column to switch to hex view, and reduce size of window to fit 8 groups of bytes. Afterwards, construct new bytes to add to code cave, and notice where each byte goes in relation to the kernel offsets. Simply copy and paste into Hex Fiend at the appropriate line as below and save file (as a copy)
Line 001A0: 10FF 2FE1 FEFF FFEA 034A 044B C250 044A
Line 001B0: 044B C250 1AF0 FABA 0120 7047 2CCB 7200
Line 001C0: 0020 0020 7ACC E400 0000 0000 0000 0000
  • Open edited file in IDA. Select line at 1A8, and press "cmd+G" to enter thumb mode and enter "0x1" for Value. Afterwards, press "C" to convert code and lastly, press "P" to create new subroutine on line 1A8. It will look like this, where you can see the offsets that we found and there corresponding patches:
ROM:000001A8 sub_1A8                                 ; CODE XREF: sub_1A048+154p
ROM:000001A8
ROM:000001A8
ROM:000001A8
ROM:000001A8                 LDR             R2, =0x47702001
ROM:000001AA                 LDR             R3, =0x72CB2C
ROM:000001AC                 STR             R2, [R0,R3]
ROM:000001AE                 LDR             R2, =0x20002000
ROM:000001B0                 LDR             R3, =0xE4CC7A
ROM:000001B2                 STR             R2, [R0,R3]
ROM:000001B4                 B.W             loc_1A7AC
ROM:000001B4 ; End of function sub_1A8
ROM:000001B4
ROM:000001B4 ; ---------------------------------------------------------------------------
ROM:000001B8 dword_1B8       DCD 0x47702001          ; DATA XREF: sub_1A8r
ROM:000001BC dword_1BC       DCD 0x72CB2C            ; DATA XREF: sub_1A8+2r
ROM:000001C0 dword_1C0       DCD 0x20002000          ; DATA XREF: sub_1A8+6r
ROM:000001C4 dword_1C4       DCD 0xE4CC7A            ; DATA XREF: sub_1A8+8r

Also, here you can see the "1B4" that we chose earlier for branch.

2) Goto "sub_1A7AC" (where we found "0xFEEDFACE"), then go to Edit->Functions->Delete Function and confirm

3) Highlight the newly deleted area, and go to Edit->Functions->Append Function Tail, and select "sub_1A8"

4) In IDA's right panel, search for "loc_1A7AC". This will be found as part of a BL as below.

ROM:0001A194 loc_1A194                               ; CODE XREF: sub_1A048+136j
ROM:0001A194                 CMP             R1, #0
ROM:0001A196                 BEQ             loc_1A0F0
ROM:0001A198                 MOV             R0, R6
ROM:0001A19A                 STR             R1, [SP,#0x80+var_5C]
ROM:0001A19C                 BL              loc_1A7AC
ROM:0001A1A0                 CMP             R0, #1

In this instruction, we need to change the BL to be the new "sub_1A8" instead of "loc_1A7AC". It will be from "1A19C" to "1A8" so E6 F7 04 F8 needs to be patched at beginning as shown earlier.

5) In IDA's right panel, search for "0xBFF01199", and change to "0x80000000". This will be 00 00 00 80 in bytes.

This patch is needed for TBD

6) In IDA's right panel, search for "0x496D6733", and delete the sub after it "sub_17F54"

ROM:00017F48 ; ---------------------------------------------------------------------------
ROM:00017F4A                 ALIGN 4
ROM:00017F4C dword_17F4C     DCD 0x496D6733          ; DATA XREF: sub_17E9C+14r
ROM:00017F50 dword_17F50     DCD 0x20001             ; DATA XREF: sub_17E9C+5Cr
ROM:00017F54
ROM:00017F54 ; =============== S U B R O U T I N E =======================================
ROM:00017F54
ROM:00017F54 ; Attributes: bp-based frame
ROM:00017F54
ROM:00017F54 sub_17F54                               ; CODE XREF: sub_18610+1A4p
ROM:00017F54
ROM:00017F54 var_58          = -0x58
ROM:00017F54 var_54          = -0x54
ROM:00017F54 var_50          = -0x50
ROM:00017F54 var_4C          = -0x4C
ROM:00017F54 var_48          = -0x48
ROM:00017F54 var_44          = -0x44
ROM:00017F54 var_40          = -0x40
ROM:00017F54 var_3C          = -0x3C
ROM:00017F54 var_38          = -0x38
ROM:00017F54 var_34          = -0x34
ROM:00017F54 var_30          = -0x30
ROM:00017F54 var_1C          = -0x1C
ROM:00017F54
ROM:00017F54                 PUSH            {R4-R7,LR}
ROM:00017F56                 ADD             R7, SP, #0xC
ROM:00017F58                 PUSH.W          {R8,R10,R11}
ROM:00017F5C                 SUB             SP, SP, #0x40
ROM:00017F5E                 MOVW            R6, #0x5394
ROM:00017F62                 MOV             R8, R0
ROM:00017F64                 MOVT.W          R6, #0xBFF4
ROM:00017F68                 MOV             R11, R2
ROM:00017F6A                 LDR             R6, [R6]

This patch is needed for TBD

7) In IDA's right panel, search for BL loc_17F54 found in this instruction:

ROM:0001878E loc_1878E                               ; CODE XREF: sub_18610+318j
ROM:0001878E                 BL              sub_38634
ROM:00018792                 MOV             R1, R0
ROM:00018794                 MOVS            R0, #0
ROM:00018796                 STRB.W          R0, [SP,#0xA8+var_6D]
ROM:0001879A                 LDR             R0, [SP,#0xA8+var_64]
ROM:0001879C                 CMP             R0, #0
ROM:0001879E                 BEQ.W           loc_18BCE
ROM:000187A2                 CMP             R1, #0
ROM:000187A4                 LDR             R5, [R6,#0x10]
ROM:000187A6                 IT NE
ROM:000187A8                 ORRNE.W         R4, R4, #4
ROM:000187AC                 ADD.W           R3, SP, #0xA8+var_6D
ROM:000187B0                 MOV             R1, R8
ROM:000187B2                 MOV             R2, R4
ROM:000187B4                 BL              loc_17F54
ROM:000187B8                 CBNZ            R0, loc_187BE
ROM:000187BA                 MOVS            R5, #0
ROM:000187BC                 B               loc_187D8

Change the BL to MOVS and STR like below. Just click on the BL, and edit bytes to be: 00 20 18 60

ROM:0001878E loc_1878E                               ; CODE XREF: sub_18610+318j
ROM:0001878E                 BL              sub_38634
ROM:00018792                 MOV             R1, R0
ROM:00018794                 MOVS            R0, #0
ROM:00018796                 STRB.W          R0, [SP,#0xA8+var_6D]
ROM:0001879A                 LDR             R0, [SP,#0xA8+var_64]
ROM:0001879C                 CMP             R0, #0
ROM:0001879E                 BEQ.W           loc_18BCE
ROM:000187A2                 CMP             R1, #0
ROM:000187A4                 LDR             R5, [R6,#0x10]
ROM:000187A6                 IT NE
ROM:000187A8                 ORRNE.W         R4, R4, #4
ROM:000187AC                 ADD.W           R3, SP, #0xA8+var_6D
ROM:000187B0                 MOV             R1, R8
ROM:000187B2                 MOV             R2, R4
ROM:000187B4                 MOVS            R0, #0
ROM:000187B6                 STR             R0, [R3]
ROM:000187B8                 CBNZ            R0, loc_187BE
ROM:000187BA                 MOVS            R5, #0
ROM:000187BC                 B               loc_187D8

This patch is needed to remove reference to deleted instruction earlier.

8) In IDA's right panel, search for CBNZ R0, loc_38E90 found in this instruction:

ROM:00038E3C loc_38E3C                               ; CODE XREF: sub_38D0C+11Ej
ROM:00038E3C                 LDR             R0, =0xBFF00328
ROM:00038E3E                 ADD             R1, SP, #0xD0+var_98
ROM:00038E40                 MOVS            R2, #0x80 ; 'Ç'
ROM:00038E42                 LDR             R0, [R0]
ROM:00038E44                 BL              sub_352DC
ROM:00038E48                 CBNZ            R0, loc_38E90
ROM:00038E4A
ROM:00038E4A loc_38E4A                               ; CODE XREF: sub_38D0C+ECj
ROM:00038E4A                 CMP.W           R8, #0
ROM:00038E4E                 BEQ             loc_38E96

We will change CBNZ to NOP, and change CMP.W below it to MOVS.W

ROM:00038E3C loc_38E3C                               ; CODE XREF: sub_38D0C+11Ej
ROM:00038E3C                 LDR             R0, =0xBFF00328
ROM:00038E3E                 ADD             R1, SP, #0xD0+var_98
ROM:00038E40                 MOVS            R2, #0x80 ; 'Ç'
ROM:00038E42                 LDR             R0, [R0]
ROM:00038E44                 BL              sub_352DC
ROM:00038E48                 NOP
ROM:00038E4A
ROM:00038E4A loc_38E4A                               ; CODE XREF: sub_38D0C+ECj
ROM:00038E4A                 MOVS.W          R8, #0
ROM:00038E4E                 BEQ             loc_38E96

Just click on the CBNZ, and edit bytes to be: 00 BF 5F F0 00 08

This patch is needed for TBD

9) Create a .patch file by diffing both files: bsdiff [original] [patched] ibec.patch

iBSS Patch

1) Load the decrypted iBSS file. In IDA's right panel, search for "0x496D6733", and delete the sub after it "sub_6228"

ROM:0000621C ; ---------------------------------------------------------------------------
ROM:0000621E                 ALIGN 0x10
ROM:00006220 dword_6220      DCD 0x496D6733          ; DATA XREF: sub_6170+14r
ROM:00006224 dword_6224      DCD 0x20001             ; DATA XREF: sub_6170+5Cr
ROM:00006228
ROM:00006228 ; =============== S U B R O U T I N E =======================================
ROM:00006228
ROM:00006228 ; Attributes: bp-based frame
ROM:00006228
ROM:00006228 sub_6228                                ; CODE XREF: sub_655C+126p
ROM:00006228
ROM:00006228 var_58          = -0x58
ROM:00006228 var_54          = -0x54
ROM:00006228 var_50          = -0x50
ROM:00006228 var_4C          = -0x4C
ROM:00006228 var_48          = -0x48
ROM:00006228 var_44          = -0x44
ROM:00006228 var_40          = -0x40
ROM:00006228 var_3C          = -0x3C
ROM:00006228 var_38          = -0x38
ROM:00006228 var_34          = -0x34
ROM:00006228 var_30          = -0x30
ROM:00006228 var_1C          = -0x1C
ROM:00006228
ROM:00006228                 PUSH            {R4-R7,LR}
ROM:0000622A                 ADD             R7, SP, #0xC
ROM:0000622C                 PUSH.W          {R8,R10,R11}
ROM:00006230                 SUB             SP, SP, #0x40
ROM:00006232                 MOVW            R6, #0x3090
ROM:00006236                 MOV             R8, R0
ROM:00006238                 MOVT.W          R6, #0x1001
ROM:0000623C                 MOV             R11, R2
ROM:0000623E                 LDR             R6, [R6]

This patch is needed for TBD

2) In IDA's right panel, search for BL loc_6228 found in this instruction:

ROM:0000665A loc_665A                                ; CODE XREF: sub_655C+298j
ROM:0000665A                 BL              sub_E998
ROM:0000665E                 MOV             R1, R0
ROM:00006660                 MOVS            R0, #0
ROM:00006662                 STRB.W          R0, [SP,#0xA0+var_6D]
ROM:00006666                 LDR             R0, [SP,#0xA0+var_64]
ROM:00006668                 CMP             R0, #0
ROM:0000666A                 BEQ.W           loc_6AC2
ROM:0000666E                 CMP             R1, #0
ROM:00006670                 LDR.W           R8, [R6,#0x10]
ROM:00006674                 IT NE
ROM:00006676                 ORRNE.W         R5, R5, #4
ROM:0000667A                 ADD.W           R3, SP, #0xA0+var_6D
ROM:0000667E                 MOV             R1, R4
ROM:00006680                 MOV             R2, R5
ROM:00006682                 BL              loc_6228
ROM:00006686                 CBNZ            R0, loc_66A0
ROM:00006688                 MOVS            R5, #0
ROM:0000668A                 B               loc_66B6

Change the BL to MOVS and STR like below. Just click on the BL, and edit bytes to be: 00 20 18 60

ROM:0000665A loc_665A                                ; CODE XREF: sub_655C+298j
ROM:0000665A                 BL              sub_E998
ROM:0000665E                 MOV             R1, R0
ROM:00006660                 MOVS            R0, #0
ROM:00006662                 STRB.W          R0, [SP,#0xA0+var_6D]
ROM:00006666                 LDR             R0, [SP,#0xA0+var_64]
ROM:00006668                 CMP             R0, #0
ROM:0000666A                 BEQ.W           loc_6AC2
ROM:0000666E                 CMP             R1, #0
ROM:00006670                 LDR.W           R8, [R6,#0x10]
ROM:00006674                 IT NE
ROM:00006676                 ORRNE.W         R5, R5, #4
ROM:0000667A                 ADD.W           R3, SP, #0xA0+var_6D
ROM:0000667E                 MOV             R1, R4
ROM:00006680                 MOV             R2, R5
ROM:00006682                 MOVS            R0, #0
ROM:00006684                 STR             R0, [R3]
ROM:00006686                 CBNZ            R0, loc_66A0
ROM:00006688                 MOVS            R5, #0
ROM:0000668A                 B               loc_66B6

This patch is needed to remove reference to deleted instruction earlier.

3) In IDA's right panel, search for CBNZ R0, loc_38E90 found in this instruction:

ROM:0000F004 loc_F004                                ; CODE XREF: sub_EED4+11Ej
ROM:0000F004                 LDR             R0, =0x10000328
ROM:0000F006                 ADD             R1, SP, #0xD0+var_98
ROM:0000F008                 MOVS            R2, #0x80 ; 'Ç'
ROM:0000F00A                 LDR             R0, [R0]
ROM:0000F00C                 BL              sub_E138
ROM:0000F010                 CBNZ            R0, loc_F058
ROM:0000F012
ROM:0000F012 loc_F012                                ; CODE XREF: sub_EED4+ECj
ROM:0000F012                 CMP.W           R8, #0
ROM:0000F016                 BEQ             loc_F05E

We will change CBNZ to NOP, and change CMP.W below it to MOVS.W

ROM:0000F004 loc_F004                                ; CODE XREF: sub_EED4+11Ej
ROM:0000F004                 LDR             R0, =0x10000328
ROM:0000F006                 ADD             R1, SP, #0xD0+var_98
ROM:0000F008                 MOVS            R2, #0x80 ; 'Ç'
ROM:0000F00A                 LDR             R0, [R0]
ROM:0000F00C                 BL              sub_E138
ROM:0000F010                 NOP
ROM:0000F012
ROM:0000F012 loc_F012                                ; CODE XREF: sub_EED4+ECj
ROM:0000F012                 MOVS.W          R8, #0
ROM:0000F016                 BEQ             loc_F05E

Just click on the CBNZ, and edit bytes to be: 00 BF 5F F0 00 08

This patch is needed for TBD

4) Create a .patch file by diffing both files: bsdiff [original] [patched] ibss.patch

Create Plist File

Plist file contains info taken from Firmware Keys page. Just open a file from another bundle, and edit it to add updated keys and other info

Create Bundle

Copy the 3 patch files and the plist file to a folder, and rename folder to: "Down_iPhone5,1_9.3.3_13G34.bundle"

Credits

@xerub: creating Odysseus
/u/HaniAG: this tutorial
/u/gjest: ASR patcher
@iSuns9: providing details for kernel offsets