iOS Application TiVo Scanner
Looking at the disassembly, the object "NetworkManager" is responsible for telling the "IPScanner" object to scan the network for TiVo's (There is a "NetworkBrowser" object that uses the bonjour service to find TiVo's but I did not decide to pursue this).
Scanning Process:
- The function "startBrowser" on the NetworkManager object creates an instance of "IPScanner"
- The method "beginScan" on the IPScanner object is called
- Grabs the wifi address (XXX.XXX.XXX.XXX), omits the last "XXX"
- Passes this "XXX.XXX.XXX" address to the "testAddresses" method
- Iterate through all subnets in this IP block...
- Create a TCP Connection for the IP on port 443
- At some point, the "TcpConnectionOpenedForInput" method on IPScanner will be called by the TCP Connection.
- If connection is successful, store this host & then attempt to connect on port 31339
- While on the 443 connection, retrieve the SSL certificate from the host. Retrieve the certificate description and set this as the "TSN" for this host. This value will be in the format XXX-YYYY-ZZZZ-UUUU. The app parses out the UUUU and attempts to match up this value with a set of known TiVo certificate descriptions via OBJC_CLASS_$_NetworkManager.HardwareTypeFromBodyId()
- If port 31339 is enabled, it gets a callback and the app sets this host to have its property "HasRemote()" equal to true
; - Scan all hosts in the last subnet, look for port 443
; - If we find port 443, look for port 31339 for the same host (if found, setRemote=true)
; - Once we have scanned all, inspect the SSL security certificate for each host
; - If SSL Certificate matches getHardwareByBodyId() and certain criteria, determine the HardwareType
; - If HardwareType = 4, HasMind=true
; - If HardwareType = 5, then it is a transcoder (TiVo Stream) and put into successTranscoders, remove it from the SuccessTCDS
; - At the end of the day, *m_SuccessTranscoders & *m_SuccessTCDS will be populated, transcoders will not be in successTCDS, and non-tivos will not be in either.
Now that we know how it scans, let's figure out what it does once it finds a TiVo...
Disassembly & Comments
/* 147 */struct NetworkManager{uint8_t NSObject_opaque[4];struct TiVo_Reachability *m_wanReach;struct TiVo_Reachability *m_lanReach;struct NSMutableArray *m_delegateList;struct NetworkBrowser *m_videosBrowser;struct NetworkBrowser *m_beaconBrowser;struct NetworkBrowser *m_rpcBrowser;struct NetworkBrowser *m_remoteBrowser;struct NetworkBrowser *m_xcodeBrowser;struct LocalTivoInfo *m_connectingTiVo;struct LocalTivoInfo *m_connectingTiVoMindRpc;struct LocalTivoInfo *m_manualBeacon;struct LocalTivoInfo *m_manualMindRpc;struct TivoInfo *m_tivo;struct NSMutableArray *m_tivoList;struct NSMutableArray *m_manualTivoList;struct NSMutableArray *m_xcodeList;int m_connectionMode;int m_wanModeAuthReqId;int m_s3ModeAuthReqId;int m_lanModeAuthReqId;int m_anonymousAuthReqId;int m_lineupSearchReqId;int m_tokenAuthReqId;int m_makAuthReqId;int m_bodyConfigReqId;struct TvLineup *m_guestModeLineup;struct NSString *m_s3ModeTsn;struct UIAlertView *m_reconnectAlert;struct IPScanner *m_ipScanner;struct AuthenticationToken *m_authToken;struct NSTimer *m_scanningTimer;int m_scanningAttempt;struct RpcRequestHandler *m_requestHandler;struct RpcRequestHandler *m_debugRequestHandler;struct RpcRequestHandler *m_tokenRequestHandler;struct TcpRemote *m_s3TcpRemote;struct NSDate *m_enteredForegroundDate;struct NSDate *m_enteredBackgroundDate;struct NSString *m_ipAddressWhenBackgrounded;struct NSTimer *m_reconnectTimer;struct NSTimer *m_networkActivityTimer;char m_shutdownBonjourAfterScan;struct NSString *m_wanHost;int m_wanPort;char enableBonjour;char enableIPScan;char enableServerDiscovery;char overrideSupportedPlatform;char enableRpcLogging;char enableRpcPerfLogging;};
/* 152 */
struct IPScanner
{
uint8_t NSObject_opaque[4];
struct NSMutableArray *m_connections;
struct NSMutableArray *m_successTCDs;
struct NSMutableArray *m_successTranscoders;
};
NetworkManager."startBrowsing"() calls IP_Scanner; IP SCANNER; id __cdecl __IPScanner init_(struct IPScanner *self, SEL)__IPScanner_init_; Calling SP:; -0x04 ? R8 is stored here; -0x08 ? _OBJC_CLASS_$_IPScanner is stored here; -0x12 ? This value is passed as the objc_super in objc_msgSendSuper2(struct objc_super *super, SEL op, ...)var_18= -0x18var_14= -0x14var_10= -0x10PUSH {R4-R7,LR} ; Push registers R4-R7 & the link register onto the stackADD R7, SP, #0xC ; Add 0xC (d12) to the stack pointer and store the value in R7; TODO - Why did we offset from the stack pointer?STR.W R8, [SP,#0xC+var_10]! ; Store R8 on the stack (address -0x04), auto-increment the SP to -0x04; Add (0xc + -0x10) = -0x04 [d12 - d16 = -d4] to the stack pointer, then store the value of R8 there; NOTE: This is the 1st argument (descending) on the stack!SUB SP, SP, #8 ; Subtract 8 from the stack pointer, the SP is now -0x12MOV R2, (classRef_IPScanner_0 - 0xD9C8E) ; classRef_IPScanner_0MOV R1, (selRef_init - 0xD9C90) ; selRef_initADD R2, PC ; classRef_IPScanner_0ADD R1, PC ; selRef_init ("init")STR R0, [SP,#0x18+var_18] ; Store R0 on the stack (address -0x12).; Add (0x18 + -0x18) = 0x00 [d24 - d24 = d0] to the stack pointer, then store the value of R0 there; NOTE: This is the 4th argument (descending) on the stack!LDR R0, [R2] ; _OBJC_CLASS_$_IPScannerLDR R1, [R1] ; "init"STR R0, [SP,#0x18+var_14] ; Store R0 (_OBJC_CLASS_$_IPScanner) on the stack (address -0x08); Add (0x18 + -0x14) = 0x04 [d24 - d20 = d4] to the stack pointer, then store the address in R0; NOTE: This is the 3rd argument (descending) on the stack!; TOOD: This method does not appear to do anything since R0 is immediately overwritten?MOV R0, SP ; Copy the stack pointer (-0x12) to R0BLX _objc_msgSendSuper2 ; OBJC_EXPORT id objc_msgSendSuper2(struct objc_super *super [R0], SEL op, ... [R1]); NOTE: This will return the memory pointer to the object we createdMOV R4, R0 ; Copy R0 to R4CMP R4, #0 ; Compare R4 to 0BEQ loc_D9D24 ; If R4 is 0, branch (this is probably a null check); On success:; Allocate a mutable array with initial capacity of 0, store the memory pointer to this mutable array in offset 0x04 of the IPScanner memory pointer (object property *m_connections); Allocate a mutable array with initial capacity of 2, store the memory pointer to this mutable array in offset 0x08 of the IPScanner memory pointer (object property *m_successTCDs); Allocate a mutable array with initial capacity of 1, store the memory pointer to this mutable array in offset 0x0C of the IPScanner memory pointer (object property *m_successTranscoders); IPScanner - (void)beginScan; Attributes: bp-based frame; void __cdecl __IPScanner beginScan_(struct IPScanner *self, SEL)__IPScanner_beginScan_PUSH {R4-R7,LR} ;ADD R7, SP, #0xC ;PUSH.W {R8,R10,R11} ;SUB SP, SP, #8 ;MOV R11, R0 ;; Clear all instances from *m_successTCDSMOV R0, (_OBJC_IVAR_$_IPScanner.m_successTCDs - 0xD9EC8) ; NSMutableArray *m_successTCDs;MOVW R1, #0x4E1E ;ADD R0, PC ; NSMutableArray *m_successTCDs; ;MOVT.W R1, #0x45 ;ADD R1, PC ; selRef_removeAllObjects ;LDR R0, [R0] ; NSMutableArray *m_successTCDs; ;LDR R5, [R1] ; "removeAllObjects" ;LDR.W R0, [R11,R0] ;MOV R1, R5 ;BLX _objc_msgSend ;; Clear all instances from *m_successTranscodersMOVW R0, #0xB330 ;MOV R1, R5MOVT.W R0, #0x4AADD R0, PC ; NSMutableArray *m_successTranscoders;LDR R0, [R0] ; NSMutableArray *m_successTranscoders;LDR.W R0, [R11,R0]BLX _objc_msgSend; Clear all instances from *m_connectionsMOVW R0, #0xB312MOV R1, R5MOVT.W R0, #0x4AADD R0, PC ; NSMutableArray *m_connections;LDR R0, [R0] ; NSMutableArray *m_connections;LDR.W R0, [R11,R0]BLX _objc_msgSend; Retrieve the "wifiIPAddress" and set its value to R5MOV R0, (selRef_wifiIPAddress - 0xD9F12) ; selRef_wifiIPAddressADD R0, PC ; selRef_wifiIPAddressLDR R1, [R0] ; "wifiIPAddress"MOV R0, R11BLX _objc_msgSendMOV R5, R0; Logging, pass our "wifiIPAddress" alongMOV R0, (cfstr_IpScannerStart - 0xD9F28) ; "IP SCANNER: Starting IP Address:%@"MOV R1, R5ADD R0, PC ; "IP SCANNER: Starting IP Address:%@"BLX _NSLog; Split the "wifiIPAddress" value by ".", store the result in R6MOV R0, (selRef_componentsSeparatedByString_ - 0xD9F3A) ; selRef_componentsSeparatedByString_MOVW R2, #0xE0B8ADD R0, PC ; selRef_componentsSeparatedByString_MOVT.W R2, #0x4AADD R2, PC ; "."LDR R1, [R0] ; "componentsSeparatedByString:"MOV R0, R5BLX _objc_msgSendMOV R6, R0; Retrieve the count of the split, If it does not have 4 parts, branchMOV R0, (selRef_count - 0xD9F54) ; selRef_countADD R0, PC ; selRef_countLDR R1, [R0] ; "count"MOV R0, R6BLX _objc_msgSendCMP R0, #4BNE loc_D9FC0; if(String.Split(WifiIPAddress,".") == 4){WifiIPAddress_in_X.X.X._format; Retrieve value at index [0] in the array created by the String.Split(), store it in R10MOVW R1, #0xAE54MOVS R2, #0MOVT.W R1, #0x45MOV R0, (selRef_objectAtIndex_ - 0xD9F76) ; selRef_objectAtIndex_ADD R1, PC ; classRef_NSStringADD R0, PC ; selRef_objectAtIndex_LDR.W R8, [R1] ; _OBJC_CLASS_$_NSStringLDR R5, [R0] ; "objectAtIndex:"MOV R0, R6MOV R1, R5BLX _objc_msgSendMOV R10, R0; Retrieve value at index [1] in the array created by the String.Split(), store it in R4MOV R0, R6MOV R1, R5MOVS R2, #1BLX _objc_msgSendMOV R4, R0; Retrieve value at index [2] in the array created by the String.Split(), store it in R5MOV R0, R6MOV R1, R5MOVS R2, #2BLX _objc_msgSendMOV R5, R0; Call NSString.StringWithFormat("%@.%@.%@.",), store its value in R5MOV R0, (selRef_stringWithFormat_ - 0xD9FAC) ; selRef_stringWithFormat_MOVW R2, #0x47D6ADD R0, PC ; selRef_stringWithFormat_MOVT.W R2, #0x4BADD R2, PC ; "%@.%@.%@."MOV R3, R10 ; First parameter of StringWithFormat is R3, which is our index [0]LDR R1, [R0] ; "stringWithFormat:"MOV R0, R8STRD.W R4, R5, [SP] ; Push R4 (index [1]) & R5 (index [2]) onto the stackBLX _objc_msgSendMOV R5, R0; }; At this point, our base IP address is stored in R5, assumed to be in the "X.X.X" formatloc_D9FC0; Log our base ip addressMOVW R0, #0x47CAMOV R1, R5MOVT.W R0, #0x4BADD R0, PC ; "IP SCANNER: Base IP Address:%@"BLX _NSLog; Execute IPScanner.testAddresses("X.X.X")MOVW R0, #0x7EE6MOV R2, R5MOVT.W R0, #0x45ADD R0, PC ; selRef_testAddresses_LDR R1, [R0] ; "testAddresses:"MOV R0, R11ADD SP, SP, #8POP.W {R8,R10,R11}POP.W {R4-R7,LR}B.W j__objc_msgSend; End of function -[IPScanner beginScan]; IPScanner - (void)testAddresses:(id); Attributes: bp-based frame; void __cdecl __IPScanner testAddresses__(struct IPScanner *self, SEL, id)__IPScanner_testAddresses__; Local Variables:__text:000D9DA8 Counter = -0x3C__text:000D9DA8 var_38 = -0x38__text:000D9DA8 RefInit = -0x34__text:000D9DA8 RefSetDelegate = -0x30__text:000D9DA8 RefOpenWithHost = -0x2C__text:000D9DA8 RefConnections = -0x28__text:000D9DA8 RefAddObject = -0x24__text:000D9DA8 RefRelease = -0x20; Parameter (id)__text:000D9DA8 Id = -0x1C ; PARAMETER; Initialize references to things before we loop ...__text:000D9DA8 PUSH {R4-R7,LR}__text:000D9DAA ADD R7, SP, #0xC__text:000D9DAC PUSH.W {R8,R10,R11}__text:000D9DB0 SUB SP, SP, #0x24__text:000D9DB2 STR R2, [SP,#0x3C+Id] ; Save our "id" in R2 to the stack__text:000D9DB4 MOV R2, (_OBJC_IVAR_$_IPScanner.m_connections - 0xD9DCE) ; NSMutableArray *m_connections;__text:000D9DBC MOV R3, (selRef_addObject_ - 0xD9DE8) ; selRef_addObject___text:000D9DC4 MOV R5, R0__text:000D9DC6 MOVW R0, #0x4F30__text:000D9DCA ADD R2, PC ; NSMutableArray *m_connections;__text:000D9DCC MOVT.W R0, #0x45__text:000D9DD0 MOV R4, (selRef_release - 0xD9DEA) ; selRef_release__text:000D9DD8 MOV R1, (selRef_init - 0xD9DF2) ; selRef_init__text:000D9DE0 MOVW R6, #0x5C64__text:000D9DE4 ADD R3, PC ; selRef_addObject___text:000D9DE6 ADD R4, PC ; selRef_release__text:000D9DE8 MOVT.W R6, #0x45__text:000D9DEC ADD R0, PC ; selRef_setDelegate___text:000D9DEE ADD R1, PC ; selRef_init__text:000D9DF0 ADD R6, PC ; selRef_openWithHost_port_SSLDesc_errorStr___text:000D9DF2 LDR R4, [R4] ; "release"__text:000D9DF4 MOV.W R8, #0 ; Initialize counter loop to 0__text:000D9DF8 LDR R3, [R3] ; "addObject:"__text:000D9DFA LDR R2, [R2] ; NSMutableArray *m_connections;__text:000D9DFC STR R3, [SP,#0x3C+RefAddObject]__text:000D9DFE STR R4, [SP,#0x3C+RefRelease]__text:000D9E00 STR R2, [SP,#0x3C+RefConnections]__text:000D9E02 MOVW R2, #0x4DB6__text:000D9E06 LDR R3, [R6] ; "openWithHost:port:SSLDesc:errorStr:"__text:000D9E08 MOVT.W R2, #0x45__text:000D9E0C LDR R0, [R0] ; "setDelegate:"__text:000D9E0E ADD R2, PC ; selRef_alloc__text:000D9E10 LDR R1, [R1] ; "init"__text:000D9E12 STR R3, [SP,#0x3C+RefOpenWithHost]__text:000D9E14 STR R0, [SP,#0x3C+RefSetDelegate]__text:000D9E16 STR R1, [SP,#0x3C+RefInit]__text:000D9E18 MOV R0, (selRef_stringWithFormat_ - 0xD9E28) ; selRef_stringWithFormat___text:000D9E20 LDR.W R10, [R2] ; "alloc"__text:000D9E24 ADD R0, PC ; selRef_stringWithFormat___text:000D9E26 LDR.W; This loop will iterate over X.X.X.0 through X.X.X.255IP_Iterations_Loop; Create our X.X.X.i string using our counter value, save the value into R6MOVW R0, #0xAF8CMOV R1, R11MOVT.W R0, #0x45STR.W R8, [SP,#0x3C+refTopOfStack] ; Update the stack counter with the real counters value, this will also be the 3rd argument for the string formatterADD R0, PC ; classRef_NSStringLDR R0, [R0] ; _OBJC_CLASS_$_NSStringMOV R2, (cfstr_D_4 - 0xD9E4A) ; "%@%d"LDR R3, [SP,#0x3C+Id]ADD R2, PC ; "%@%d"BLX _objc_msgSendMOV R6, R0; Create a TCPConnection objectMOV R0, (classRef_TcpConnection - 0xD9E5C) ; classRef_TcpConnectionMOV R1, R10ADD R0, PC ; classRef_TcpConnectionLDR R0, [R0] ; _OBJC_CLASS_$_TcpConnectionBLX _objc_msgSend; Call TCPConnection.Init();LDR R1, [SP,#0x3C+RefInit]BLX _objc_msgSend; Call TCPConnection.SetDelegate(*IPScanner);; NOTE: This appears to be a register that allows IPScanner to handle callbacks from TCPConnectionLDR R1, [SP,#0x3C+RefSetDelegate]MOV R2, R5 ; Set R5 equal to our current IPScanner objectMOV R4, R0 ; Set R4 equal to our TCPConnection object (this method must return a different object and override R0)BLX _objc_msgSend; Execute TCPConnection("OpenWithHost:port:SSLDesc:errorStr")( "X.X.X.i", "443" )MOVS R1, #3MOVS R0, #0STR R1, [SP,#0x3C+refTopOfStack] ; set SSLDescMOV R2, R6 ; Put our calculated IP into R6, (Parameter 1)STR R0, [SP,#0x3C+var_38] ; set ErrorMessageMOV R0, R4 ; Set R0 = TCPConnection ObjectLDR R1, [SP,#0x3C+RefOpenWithHost] ; Load "openWithHost:port:SSLDesc:errorStr:" into R1MOVW R3, #0x1BB ; Passed in a parameter of "443"BLX _objc_msgSend; *m_connections.AddObject(TCPConnection) - Add our TCPConnection to the m_connections arrayLDR R0, [SP,#0x3C+RefConnections]MOV R2, R4LDR R1, [SP,#0x3C+RefAddObject]LDR R0, [R5,R0]BLX _objc_msgSend; TCPConnection.Release()LDR R1, [SP,#0x3C+RefRelease]MOV R0, R4BLX _objc_msgSend; Increment the counterADD.W R8, R8, #1CMP.W R8, #0x100 ; 256 (Full IP Range); If(counter != 256){BNE IP_Iterations_Loop; }; CleanupADD SP, SP, #0x24POP.W {R8,R10,R11}POP {R4-R7,PC}; End of function -[IPScanner testAddresses:]IPScanner - (void)TcpConnectionOpenedForInput:(id)Attributes: bp-based frame; void __cdecl __IPScanner TcpConnectionOpenedForInput__(struct IPScanner *self, SEL, TcpConnectionId)__IPScanner_TcpConnectionOpenedForInput__; Local variables__text:000DA2F8 var_48 = -0x48__text:000DA2F8 var_44 = -0x44__text:000DA2F8 var_40 = -0x40__text:000DA2F8 valPort = -0x3C__text:000DA2F8 refObjectAtIndex= -0x38__text:000DA2F8 refAddress = -0x34__text:000DA2F8 refIsEqualTostring= -0x30__text:000DA2F8 refSetHasRemote = -0x2C__text:000DA2F8 var_28 = -0x28__text:000DA2F8 refCountOrAlloc = -0x24__text:000DA2F8 refHost = -0x20; Parameters__text:000DA2F8 TcpConnectionId = -0x1C; Typical Init shit, put TcpConnectionId into R6, put self reference into R8__text:000DA2F8 PUSH {R4-R7,LR}__text:000DA2FA ADD R7, SP, #0xC__text:000DA2FC PUSH.W {R8,R10,R11}__text:000DA300 SUB SP, SP, #0x30__text:000DA302 MOV R6, R2__text:000DA304 MOV R8, R0__text:000DA306 STR R6, [SP,#0x48+TcpConnectionId]; Retrieve the host from the TCPConnection, put it into R5__text:000DA308 MOV R0, (selRef_host - 0xDA314) ; selRef_host__text:000DA310 ADD R0, PC ; selRef_host__text:000DA312 LDR R1, [R0] ; "host"__text:000DA314 MOV R0, R6__text:000DA316 STR R1, [SP,#0x48+refHost]__text:000DA318 BLX _objc_msgSend__text:000DA31C MOV R5, R0; Retrieve the port from the TCPConnection, put it into R2__text:000DA31E MOV R0, (selRef_port - 0xDA32A) ; selRef_port__text:000DA326 ADD R0, PC ; selRef_port__text:000DA328 LDR R4, [R0] ; "port"__text:000DA32A MOV R0, R6__text:000DA32C MOV R1, R4__text:000DA32E BLX _objc_msgSend__text:000DA332 MOV R2, R0; Log some shit__text:000DA334 MOV R0, (cfstr_Tcpconnectio_3 - 0xDA342) ; "TcpConnectionOpenedForInput ip:%@ port:%d"__text:000DA33C MOV R1, R5__text:000DA33E ADD R0, PC ; "TcpConnectionOpenedForInput ip:%@ port:%d"__text:000DA340 MOV R5, R8__text:000DA342 BLX _NSLog; Retrieve the port from the TCPConnection (again), put it into R10__text:000DA346 MOV R0, R6__text:000DA348 MOV R1, R4__text:000DA34A BLX _objc_msgSend__text:000DA34E MOV R10, R0; Retrieve the port from the TCPConnection (again), store the value of the port into a local variable,__text:000DA350 MOV R0, R6__text:000DA352 MOV R1, R4__text:000DA354 STR.W R10, [SP,#0x48+valPort]__text:000DA358 BLX _objc_msgSend__text:000DA35C MOVW R1, #0xAEA6; Store the port in R4, retrieve the count of *m_successTCDs array__text:000DA35C MOVW R1, #0xAEA6__text:000DA360 MOV R4, R0__text:000DA362 MOVT.W R1, #0x4A__text:000DA366 MOVW R0, #0x48E0__text:000DA36A ADD R1, PC ; NSMutableArray *m_successTCDs;__text:000DA36C MOVT.W R0, #0x45__text:000DA370 ADD R0, PC ; selRef_count__text:000DA372 LDR.W R8, [R1] ; NSMutableArray *m_successTCDs;__text:000DA376 LDR R1, [R0] ; "count"__text:000DA378 STR R1, [SP,#0x48+refCountOrAlloc]__text:000DA37A LDR.W R0, [R5,R8]__text:000DA37E BLX _objc_msgSend; If port is = 443, set R1 equal to 1 (this is a flag)__text:000DA382 MOVW R1, #0x1BB__text:000DA386 CMP R10, R1__text:000DA388 MOV.W R1, #0__text:000DA38C MOV.W R2, #0__text:000DA390 IT EQ__text:000DA392 MOVEQ R1, #1; Store our flag, if the port is 0x7A6B (31339) set R2 equal to 1 (this is a flag)__text:000DA394 MOVW R3, #0x7A6B__text:000DA398 STR R1, [SP,#0x48+FlagIsSSL]__text:000DA39A CMP R4, R3__text:000DA39C IT EQ__text:000DA39E MOVEQ R2, #1; Store our flag, check if the count of *m_successTCDS is 0, branch if it is zero__text:000DA3A0 CMP R0, #0__text:000DA3A2 STR R2, [SP,#0x48+FlagIsPort31339]__text:000DA3A4 BEQ; if(count(*m_successTCDs) != 0){; CODE IGNORED - Simply checks if the array already has this HOST, if it does, updates the HasRemote() using the 31339 port flag (if 31339 port, HasRemote=true); }loc_DA43C; Allocate space for an IPScannerInfo object; Store "alloc" into "refCountOrAlloc"MOV R1, (selRef_alloc - 0xDA450) ; selRef_allocMOV R0, (classRef_IPScannerInfo - 0xDA452) ; classRef_IPScannerInfoADD R1, PC ; selRef_allocADD R0, PC ; classRef_IPScannerInfoLDR R1, [R1] ; "alloc"LDR R0, [R0] ; _OBJC_CLASS_$_IPScannerInfoSTR R1, [SP,#0x48+refCountOrAlloc]BLX _objc_msgSend; Intialize the IPScannerInfo objectMOV R1, (selRef_init - 0xDA466) ; selRef_initADD R1, PC ; selRef_initLDR.W R10, [R1] ; "init"MOV R1, R10BLX _objc_msgSend; Save IPScannerInfo in R4, retrieve the Host from TCPConnection & store it in R2LDR R6, [SP,#0x48+TcpConnectionId]MOV R4, R0LDR R1, [SP,#0x48+refHost]MOV R0, R6BLX _objc_msgSendMOV R2, R0; Call IPScannerInfo."setAddress:"(TCPConnection."Host")MOV R0, (selRef_setAddress_ - 0xDA488) ; selRef_setAddress_ADD R0, PC ; selRef_setAddress_LDR R1, [R0] ; "setAddress:"MOV R0, R4BLX _objc_msgSend; Call IPScannerInfo."setHasVideos:"(FlagIsSSL)MOV R0, (selRef_setHasVideos_ - 0xDA49C) ; selRef_setHasVideos_LDR R2, [SP,#0x48+FlagIsSSL]ADD R0, PC ; selRef_setHasVideos_LDR R1, [R0] ; "setHasVideos:"MOV R0, R4BLX _objc_msgSend; Call IPScannerInfo."setLastConnection:"(*TCPConnection)MOVW R0, #0x7A20MOV R2, R6MOVT.W R0, #0x45ADD R0, PC ; selRef_setLastConnection_LDR R1, [R0] ; "setLastConnection:"MOV R0, R4BLX _objc_msgSend; Check if port is 443, branch if it is notLDR R0, [SP,#0x48+valPort]MOVW R1, #0x1BBCMP R0, R1BNE loc_DA560; if(Port == 443){; Call *m_successTCDs."addObject:"(*IPScannerInfo)MOVW R0, #0x4716MOV R2, R4MOVT.W R0, #0x45ADD R0, PC ; selRef_addObject_LDR.W R11, [R0] ; "addObject:"LDR.W R0, [R5,R8]MOV R1, R11BLX _objc_msgSend; Create a TcpConnection object - Call _OBJC_CLASS_$_TcpConnection."alloc"()MOV R0, (classRef_TcpConnection - 0xDA4E8) ; classRef_TcpConnectionLDR R1, [SP,#0x48+refCountOrAlloc]ADD R0, PC ; classRef_TcpConnectionLDR R0, [R0] ; _OBJC_CLASS_$_TcpConnectionBLX _objc_msgSend; Call TcpConnection."init"(), save the TcpConnection instance in R6MOV R1, R10BLX _objc_msgSendMOV R6, R0; Set the delegate of the TcpConnection to be the IPScanner (self)MOV R0, (selRef_setDelegate_ - 0xDA502) ; selRef_setDelegate_MOV R2, R5ADD R0, PC ; selRef_setDelegate_LDR R1, [R0] ; "setDelegate:"MOV R0, R6BLX _objc_msgSend; Get IPScannerInfo."address:" and store it in R2MOV R0, (selRef_address - 0xDA514) ; selRef_addressADD R0, PC ; selRef_addressLDR R1, [R0] ; "address"MOV R0, R4BLX _objc_msgSendMOV R2, R0; Since we found a port 443 match, try to find a port 31339 match.; Call TcpConnection."selRef_openWithHost_port_SSLDesc_errorStr_"(IPScannerInfo.Address, 31339)MOV R0, (selRef_openWithHost_port_SSLDesc_errorStr_ - 0xDA52C) ; selRef_openWithHost_port_SSLDesc_errorStr_MOVW R3, #0x7A6B ; 31339ADD R0, PC ; selRef_openWithHost_port_SSLDesc_errorStr_LDR R1, [R0] ; "openWithHost:port:SSLDesc:errorStr:"MOVS R0, #0STR R0, [SP,#0x48+var_48]STR R0, [SP,#0x48+var_44]MOV R0, R6BLX _objc_msgSend; Add the new connection to our connections list; Call *m_connections."addObject:"(*TcpConnection)MOVW R0, #0xACC8MOV R1, R11MOVT.W R0, #0x4AMOV R2, R6ADD R0, PC ; NSMutableArray *m_connections;LDR R0, [R0] ; NSMutableArray *m_connections;LDR R0, [R5,R0]BLX _objc_msgSend; Call TcpConnection.Release()MOV R0, (selRef_release - 0xDA55A) ; selRef_releaseADD R0, PC ; selRef_releaseLDR R1, [R0] ; "release"MOV R0, R6BLX _objc_msgSend; }; Release IPScannerInfo object, normal cleanuploc_DA560MOV R0, (selRef_release - 0xDA56C) ; selRef_releaseADD R0, PC ; selRef_releaseLDR R1, [R0] ; "release"MOV R0, R4ADD SP, SP, #0x30POP.W {R8,R10,R11}POP.W {R4-R7,LR}B.W j__objc_msgSend; NOTE: NetworkManager.ScanningTimeout() calls IPScanner.EndScan(); The jist of this function is that it will take *m_successTCDs items and determine if they have minds, are transcoders, etc based on their TSN (SSL Cert Description); If an item in *m_successTCDS is a transcoder, it will be removed from the array and added to *m_successTranscoders/; No matter what happens, at the end all objects will be removed from *m_connections;IPScanner - (void)endScanAttributes: bp-based framevoid __cdecl __IPScanner endScan_(struct IPScanner *self, SEL)__IPScanner_endScan_ ; DATA XREF: __objc_const:004DD6F8 o; Internal attributes__text:000D9FF0 refSelf = -0x78__text:000D9FF0 valTSNPart2 = -0x74__text:000D9FF0 valTSNPart3 = -0x70__text:000D9FF0 strLastConnection= -0x6C__text:000D9FF0 strServerCertDescription= -0x68__text:000D9FF0 strComponentsSeparatedByString= -0x64__text:000D9FF0 strStringWithFormat= -0x60__text:000D9FF0 strHardwareTypeFromBodyID= -0x5C__text:000D9FF0 refSuccessTranscoders= -0x58__text:000D9FF0 strAddObject = -0x54__text:000D9FF0 strRemoveObject = -0x50__text:000D9FF0 strSetLastConnection= -0x4C__text:000D9FF0 strDump = -0x48__text:000D9FF0 strSetHasMind = -0x44__text:000D9FF0 strAddress = -0x40__text:000D9FF0 refSuccessTCDs = -0x3C__text:000D9FF0 StrCount = -0x38__text:000D9FF0 refNSStringInstance= -0x34__text:000D9FF0 refNSStringClass= -0x30__text:000D9FF0 valIncrementerCount= -0x2C__text:000D9FF0 strObjectAtIndex= -0x28__text:000D9FF0 strSetTSN = -0x24__text:000D9FF0 strLength = -0x20; First Parameter ?; NOTE: This doesn't make much sense__text:000D9FF0 strTSN = -0x1C; Typical init, store self reference in R10__text:000D9FF0 PUSH {R4-R7,LR}__text:000D9FF2 ADD R7, SP, #0xC__text:000D9FF4 PUSH.W {R8,R10,R11}__text:000D9FF8 SUB SP, SP, #0x60__text:000D9FFA MOV R10, R0; Log__text:000D9FFC MOV R0, (cfstr_IpScannerEndSc - 0xDA008) ; "IP SCANNER: end scan"__text:000DA004 ADD R0, PC ; "IP SCANNER: end scan"__text:000DA006 BLX _NSLog; Get the count of items in *m_successTCDS__text:000DA00A MOV R1, (_OBJC_IVAR_$_IPScanner.m_successTCDs - 0xDA01A) ; NSMutableArray *m_successTCDs;__text:000DA012 MOVW R0, #0x4C34__text:000DA016 ADD R1, PC ; NSMutableArray *m_successTCDs;__text:000DA018 MOVT.W R0, #0x45__text:000DA01C ADD R0, PC ; selRef_count__text:000DA01E LDR R6, [R1] ; NSMutableArray *m_successTCDs;__text:000DA020 LDR R1, [R0] ; "count"__text:000DA022 STR R6, [SP,#0x78+refSuccessTCDs]__text:000DA024 LDR.W R0, [R10,R6]__text:000DA028 STR R1, [SP,#0x78+strCount]__text:000DA02A BLX _objc_msgSend; Store the count-1 (last index) of *m_successTCDS in R2 (this will be used as the incrementer later); If there is not at least 1 item in *m_successTCDS, branch__text:000DA02E SUBS R2, R0, #1__text:000DA030 CMP R2, #0__text:000DA032 BLT.W loc_DA2AA; if(count(*m_successTCDS) > 0){; Initialize properties before looping; init_before_loopMOV R3, (selRef_dump - 0xDA062) ; selRef_dumpMOV R0, (selRef_setHasMind_ - 0xDA05A) ; selRef_setHasMind_MOV R9, (selRef_removeObject_ - 0xDA07A) ; selRef_removeObject_MOV R5, (selRef_address - 0xDA060) ; selRef_addressADD R0, PC ; selRef_setHasMind_MOVW R1, #0x4B6EADD R5, PC ; selRef_addressADD R3, PC ; selRef_dumpMOVT.W R1, #0x45MOVW R4, #0x7E52LDR R0, [R0] ; "setHasMind:"MOVT.W R4, #0x45LDR R5, [R5] ; "address"STR R0, [SP,#0x78+strSetHasMind]ADD R1, PC ; selRef_addObject_LDR R0, [R3] ; "dump"ADD R9, PC ; selRef_removeObject_STR R5, [SP,#0x78+strAddress]ADD R4, PC ; selRef_setLastConnection_STR R0, [SP,#0x78+strDump]MOV R0, (_OBJC_IVAR_$_IPScanner.m_successTranscoders - 0xDA08C) ; NSMutableArray *m_successTranscoders;LDR R3, [R4] ; "setLastConnection:"ADD R0, PC ; NSMutableArray *m_successTranscoders;LDR.W R11, [R9] ; "removeObject:"LDR R1, [R1] ; "addObject:"LDR R0, [R0] ; NSMutableArray *m_successTranscoders;STR R3, [SP,#0x78+strSetLastConnection]STR.W R11, [SP,#0x78+strRemoveObject]STR R1, [SP,#0x78+strAddObject]STR R0, [SP,#0x78+refSuccessTranscoders]MOV R0, (selRef_hardwareTypeFromBodyID_tsnIndex_ - 0xDA0A8) ; selRef_hardwareTypeFromBodyID_tsnIndex_ADD R0, PC ; selRef_hardwareTypeFromBodyID_tsnIndex_LDR R0, [R0] ; "hardwareTypeFromBodyID:tsnIndex:"STR R0, [SP,#0x78+strHardwareTypeFromBodyID]MOV R0, (selRef_stringWithFormat_ - 0xDA0B6) ; selRef_stringWithFormat_ADD R0, PC ; selRef_stringWithFormat_LDR R0, [R0] ; "stringWithFormat:"STR R0, [SP,#0x78+strStringWithFormat]MOV R0, (selRef_length - 0xDA0C4) ; selRef_lengthADD R0, PC ; selRef_lengthLDR R0, [R0] ; "length"STR R0, [SP,#0x78+strLength]MOV R0, (selRef_componentsSeparatedByString_ - 0xDA0D2) ; selRef_componentsSeparatedByString_ADD R0, PC ; selRef_componentsSeparatedByString_LDR R0, [R0] ; "componentsSeparatedByString:"STR R0, [SP,#0x78+strComponentsSeparatedByString]MOV R0, (selRef_tsn - 0xDA0E0) ; selRef_tsnADD R0, PC ; selRef_tsnLDR R0, [R0] ; "tsn"STR R0, [SP,#0x78+strTSN]MOV R0, (selRef_setTsn_ - 0xDA0EE) ; selRef_setTsn_ADD R0, PC ; selRef_setTsn_LDR R0, [R0] ; "setTsn:"STR R0, [SP,#0x78+strSetTSN]MOV R0, (selRef_serverCertDescription - 0xDA0FC) ; selRef_serverCertDescriptionADD R0, PC ; selRef_serverCertDescriptionLDR R0, [R0] ; "serverCertDescription"STR R0, [SP,#0x78+strServerCertDescription]MOV R0, (selRef_lastConnection - 0xDA10A) ; selRef_lastConnectionADD R0, PC ; selRef_lastConnectionLDR R0, [R0] ; "lastConnection"STR R0, [SP,#0x78+strLastConnection]MOV R0, (selRef_objectAtIndex_ - 0xDA118) ; selRef_objectAtIndex_ADD R0, PC ; selRef_objectAtIndex_LDR R0, [R0] ; "objectAtIndex:"STR R0, [SP,#0x78+strObjectAtIndex]; TODObeginning_of_loop; Call m_successTCDs."ObjectAtIndex"(i), updated incrementer in memory__text:000DA11A LDR.W R0, [R10,R6]__text:000DA11E LDR R1, [SP,#0x78+strObjectAtIndex]__text:000DA120 STR R2, [SP,#0x78+valIncrementerCount]__text:000DA122 BLX _objc_msgSend; Set the retrieved *IPScannerInfo reference into R5; Retrieve the last *TCPConnection from the *IPScannerInfo__text:000DA126 LDR R1, [SP,#0x78+strLastConnection]__text:000DA128 MOV R5, R0__text:000DA12A BLX _objc_msgSend; Call *TCPConnection."ServerCertDescription"(), store value in R2__text:000DA12E LDR R1, [SP,#0x78+strServerCertDescription]__text:000DA130 BLX _objc_msgSend; Call *IPScannerInfo."SetTSN"(*ServerCertDescription); TODO - This is very important__text:000DA134 LDR R1, [SP,#0x78+strSetTSN]__text:000DA136 MOV R2, R0__text:000DA138 MOV R0, R5__text:000DA13A BLX _objc_msgSend; Call *IPScannerInfo."TSN"(), store the result in R1__text:000DA13E LDR R4, [SP,#0x78+strTSN]__text:000DA140 MOV R0, R5__text:000DA142 MOV R1, R4__text:000DA144 BLX _objc_msgSend__text:000DA148 MOV R1, R0; Log__text:000DA14A MOV R0, (cfstr_IpscannerCertD - 0xDA156) ; "IPScanner:Cert Description:%@"__text:000DA152 ADD R0, PC ; "IPScanner:Cert Description:%@"__text:000DA154 BLX _NSLog; Call *IPScannerInfo."TSN"()__text:000DA158 MOV R0, R5__text:000DA15A MOV R1, R4__text:000DA15C BLX _objc_msgSend; Call *TSN."ComponentsSeparatedByString"("-"), store result in R8__text:000DA160 LDR R1, [SP,#0x78+strComponentsSeparatedByString]__text:000DA162 MOV R2, (stru_587698 - 0xDA16E) ; "-"__text:000DA16A ADD R2, PC ; "-"__text:000DA16C BLX _objc_msgSend__text:000DA170 MOV R8, R0; Call *IPScannerInfo."TSN"()__text:000DA172 MOV R0, R5__text:000DA174 MOV R1, R4__text:000DA176 BLX _objc_msgSend; Call *IPScannerInfo."Length"(), branch if it is not equal to 18...__text:000DA17A LDR R1, [SP,#0x78+strLength]__text:000DA17C BLX _objc_msgSend__text:000DA180 CMP R0, #0x12BNE TSN_String_Invalid; if(*IPScannerInfo."Length"() != 18){; See if the count of R8 (TSN seperated by "-") is equal to 4, branch if it is notLDR R1, [SP,#0x78+strCount]MOV R0, R8BLX _objc_msgSendCMP R0, #4BNE TSN_String_Invalid; NOTE: We branch here to the ELSE statement further below!; Get the index [0] of the TSN split by "-", save it into valTSNPart1; We also save an instance of the stringClassMOVW R0, #0xAC26MOVS R2, #0MOVT.W R0, #0x45LDR.W R11, [SP,#0x78+strObjectAtIndex]ADD R0, PC ; classRef_NSStringLDR R0, [R0] ; _OBJC_CLASS_$_NSStringMOV R1, R11STR R0, [SP,#0x78+refNSStringClass]MOV R0, R8BLX _objc_msgSendSTR R0, [SP,#0x78+valTSNPart1]; Get the index [1] of the TSN split by "-" (R8), save it into R10; We also save R10 into R4 beforehandMOV R0, R8MOV R1, R11MOVS R2, #1BLX _objc_msgSendMOV R4, R10MOV R10, R0; Get the index [2] of the TSN split by "-" (R8), save it into R6MOV R0, R8MOV R1, R11MOVS R2, #2BLX _objc_msgSendMOV R6, R0; Get the index [3] of the TSN split by "-" (R8)MOV R0, R8MOV R1, R11MOVS R2, #3BLX _objc_msgSend; Save our TSN Parts to memorySTR.W R10, [SP,#0x78+refSelf] ; Save Index [1]MOV R10, R4 ; Restore R10 to be "self"STR R6, [SP,#0x78+valTSNPart2] ; Save Index [2]STR R0, [SP,#0x78+valTSNPart3] ; Save Index [3]; Call StringClass.StringWithFormat("%@%@%@%@",TSNPart1); TODO - This doesn't make sense, why are we ignoring the other TSN parts?LDR R0, [SP,#0x78+refNSStringClass] ;LDR R1, [SP,#0x78+strStringWithFormat]MOV R2, (stru_58E7C8 - 0xDA1EE) ; "%@%@%@%@"LDR R3, [SP,#0x78+valTSNPart1]ADD R2, PC ; "%@%@%@%@"LDR.W R11, [SP,#0x78+strRemoveObject]LDR R6, [SP,#0x78+refSuccessTCDs]BLX _objc_msgSend; Call *IPScannerInfo.SetTSN(StringClass.StringWithFormat("%@%@%@%@",TSNPart1))LDR R1, [SP,#0x78+strSetTSN]MOV R2, R0MOV R0, R5BLX _objc_msgSend; Determine the hardware type from the body id; NOTE: We branch here if the ServerCertDescription is not emptyDetermine_Hardware_Type; Call _OBJC_CLASS_$_NetworkManager.HardwareTypeFromBodyId(*IPScannerInfo.Tsn(),0)MOV R0, (classRef_NetworkManager - 0xDA20E) ; classRef_NetworkManagerLDR R1, [SP,#0x78+strTSN]ADD R0, PC ; classRef_NetworkManagerLDR R4, [R0] ; _OBJC_CLASS_$_NetworkManagerMOV R0, R5BLX _objc_msgSendLDR R1, [SP,#0x78+strHardwareTypeFromBodyID]MOV R2, R0MOV R0, R4MOVS R3, #0BLX _objc_msgSend; If the hardware type returned is NOT 5...branchCMP R0, #5BNE loc_DA274; if(HardwareType != 5){__text:000DA274 Not_Transcoder_Hardware; NOTE: R0 is our hardware type enum value (1-5); TODO - This logic is confusing, try to figure out what actually has a "mind", is it 2, 3, or 4? or a combo?; If HardwareType is <= 3, branch (it does not have a mind!)__text:000DA274 SUBS R1, R0, #1 ; Add 1 to our enum value, store it in R1__text:000DA276 CMP R1, #2 ; Subtract (HardwareType-1) from 2, set the carry bit if (HardwareType-1) > 2BCC loc_DA28C ; Branch if Carry is clear (we did not go negative); If HardwareType != 4, branch (it does not have a mind)__text:000DA27A CMP R0, #3__text:000DA27C IT NE__text:000DA27E CMPNE R0, #4__text:000DA280 BEQ loc_DA28C; If we got here, HardwareType is 4; Call *IPScannerInfo.SetHasMind(1)LDR R1, [SP,#0x78+strSetHasMind]MOV R0, R5MOVS R2, #1loc_DA288BLX _objc_msgSendloc_DA28C; Call *IPScannerInfo.SetLastConnection(null)LDR R1, [SP,#0x78+strSetLastConnection]MOV R0, R5MOVS R2, #0BLX _objc_msgSend; Call *IPScannerInfo.Dump(); TODO - What does dump do? Delete it?LDR R1, [SP,#0x78+strDump]MOV R0, R5BLX _objc_msgSendB End_of_loop; } else {Transcoder_Hardware; Call *m_successfulTranscoders.AddObject(*IPScannerInfo)LDR R0, [SP,#0x78+refSuccessTranscoders]MOV R2, R5LDR R1, [SP,#0x78+strAddObject]LDR.W R0, [R10,R0]BLX _objc_msgSend; Remove from *m_successTCDsLDR.W R0, [R10,R6] ;MOV R1, R11 ; RemoveObjectMOV R2, R5 ; *IPScannerInfoB loc_DA288; }; } else if (*IPScannerInfo."Length"() != 18 || *TSN."ComponentsSeparatedByString"("-").Length() != 4){TSN_String_Invalid; Call *IPScannerInfo.TSN().Length(), check if it is equal to 0, branch if it is (0)LDR R1, [SP,#0x78+strTSN]MOV R0, R5BLX _objc_msgSendLDR R1, [SP,#0x78+strLength]BLX _objc_msgSendCMP R0, #0xFBEQ Determine_Hardware_Type; if(*IPScannerInfo.TSN().Length() != 0){; BRANCH TO "Determine Hardware Type"; }else{; Cleanup, this is not a tivo!Cleanup_Invalid_IPScannerInfo; Retrieve the address for this IPScannerInfoLDR R1, [SP,#0x78+strAddress]MOV R0, R5BLX _objc_msgSendMOV R1, R0; LogMOV R0, (cfstr_Removing - 0xDA264) ; "Removing %@"ADD R0, PC ; "Removing %@"BLX _NSLog; Call m_successTCDs.removeObject(*IPScannerInfo)LDR.W R0, [R10,R6]MOV R1, R11MOV R2, R5BLX _objc_msgSendB End_of_loop; }; }; Increment the counter, if it is not 0, continue loopingEnd_of_loopLDR R2, [SP,#0x78+valIncrementerCount]SUBS R2, #1CMP.W R2, #0xFFFFFFFFBGT.W beginning_of_loop; }; Erase all items from the *m_connections array, normal cleanup__text:000DA2AA loc_DA2AA__text:000DA2AA MOV R0, (_OBJC_IVAR_$_IPScanner.m_connections - 0xDA2BA) ; NSMutableArray *m_connections;__text:000DA2B2 MOVW R1, #0x4A2C__text:000DA2B6 ADD R0, PC ; NSMutableArray *m_connections;__text:000DA2B8 MOVT.W R1, #0x45__text:000DA2BC ADD R1, PC ; selRef_removeAllObjects__text:000DA2BE LDR R0, [R0] ; NSMutableArray *m_connections;__text:000DA2C0 LDR R1, [R1] ; "removeAllObjects"__text:000DA2C2 LDR.W R0, [R10,R0]__text:000DA2C6 ADD SP, SP, #0x60__text:000DA2C8 POP.W {R8,R10,R11}__text:000DA2CC POP.W {R4-R7,LR}__text:000DA2D0 B.W j__objc_msgSend__text:000DA2D0 ; End of function -[IPScan; NOTE: NetworkManager."hardwareTypeFromBodyID:tsnIndex"() returns an enum based on the TCD value (before the first "-") that determines what type of box it is (transcoder vs others vs minds)NetworkManager."hardwareTypeFromBodyID:tsnIndex"([String] (Server Certificate CN).Split('-')[0]) {HardwareType Enum: {0: NOT_A_TIVO1: ?? - Guess: TIVO SD?2: TIVO_HD3: S3 - Guess : Tivo Series 3? TODO4: Premiere - Guess : TIVO Premiere? TODO ; HAS MIND!5: TRANSCODER_SUPPORT - Guess : TIVO Stream;}Look up table| TSN Value | Enum |-----------------------1 12 13 14 15 1627 1640 1649 1653 1648 2652 2658 2663 26E8 26F2 26F8 2A94 5AD4 5AE4 5AF0 3A90 3A92 4AE2 4other 0-----------------------}
No comments:
Post a Comment