guino / Merkury1080P

Merkury1080P (CW017) Rooting and Customization
79 stars 16 forks source link

LSC Smart Outdoor (IP) Camera - Hack not working #42

Open EpicLPer opened 1 year ago

EpicLPer commented 1 year ago

Heya!

Bought a LSC Smart Outdoor (IP) Camera yesterday and tried this hack, but sadly it didn't seem to work. I added the camera to Tuya and had to update it before being able to use it (which probably was a mistake in hindsight).

image

The Firmware version on it right now is 2.10.36, and the only open ports I see are 53 and 6668.

If you need anything, I'm willing to open the camera up and do have soldering skills, I've also helped to dump the Sonoff cam a few years back and then figuring some things out :)

Thanks already for your help!

jonesMeUp commented 1 year ago

@guino yep, long before i put the waiting into the bg which seems to trigger a watchdog. there is no chance to wait for so long. For a test i put iirc 8 * nop instruction at the start of void ht_log_init(void) the first sub in main(). It worked without killing the log function, but we could live without the logging... My problem is the ldr part. i don't understand how to load the statusMQTT variable into r3 in assembler code. i "copied" the code block from tuya_main()

          while (statusMQTT != 1) {
            sleep(1);
          }
        0009c498 01 00 a0 e3     mov        r0,#0x1
        0009c49c 18 de fe eb     bl         <EXTERNAL>::sleep
        0009c4a0 a0 30 9f e5     ldr        r3,[PTR_DAT_0009c548]
        0009c4a4 03 30 8f e0     add        r3,pc,r3
        0009c4a8 00 30 93 e5     ldr        r3,[r3,#0x0]=>statusMQTT
        0009c4ac 01 00 53 e3     cmp        r3,#0x1
        0009c4b0 f8 ff ff 1a     bne        LAB_0009c498

into the free part of void ht_log_init(void) but i didn't get ldr to point to the statusMQTT.

guino commented 1 year ago

@jonesMeUp here's what I'd try (this will SET the statusMQTT and at the same time skip the loop):

  0009c4a0 a0 00 9f e5         ldr    r0,[0x9c548]
  0009c4a4 01 30 a0 e3         mov    r3,#0x1
  0009c4a8 00 30 00 e5         str    r3,[r0,#0x0]
  0009c4ac 01 00 53 e3         cmp    r3,#0x1
  0009c4b0 f8 ff ff 1a         bne    LAB_0009c498

YOU MUST ALSO modify the bytes on address 0x9c548 to be: 1c 4d 43 00

If that's not what you want to do you may give me some more detail... in any case, if you want to load the contents of statusMqtt (0x434dc1) into r3 the instruction should be: ldr r3,[0x9c548] along with modifying the bytes in 0x9c548 to be 1c 4d 43 00 (as I did with r0 above).

If you wanted to just set the variable from an outside script I assume that trick with echo+dd would work (as you previously confirmed): echo -en '\x01\x00\x00\x00' | dd of=/proc/$PID/mem bs=1 count=4 seek=$((0x434d1c))

guino commented 1 year ago

@jonesMeUp some other piece of information which can help.. apparently this can prevent the watchdog from resetting the device: (while true; do sleep 5; echo -n 1 > /dev/watchdog; done ) < /dev/null >& /dev/null & (basically sending 1 to /dev/watchdog every 5 seconds)

I kept my device running for a few minutes without a reboot and without anyka_ipc running that way -- however: the biggest problem is that anyka_ipc is what configures/connects the wifi on the device (so you can sync the time) so you'd have to start and configure the wifi by hand in order to get the time before running anyka_ipc. Still could be an option if all else fails.

jonesMeUp commented 1 year ago

@guino thx for your support! You misunderstood me. I used your hint to set statusMQTT in hack.sh as soon as ntpd has done its job.

What i want ito do:

Step 1:

while (statusMQTT != 1) {
   sleep(1);
 }

Place this loop at 0x00065bc8 in void ht_log_init(void) thats in main() NOT in tuya_main() There is enough "empty" space for this loop and i want to test it for sideeffects.

Step 2:

If this will work, i want to overwrite the loop in tuya_main() with a call to ht_log_init(void) (The original caller function to ht_log_init(void) will be NOP out for the testing, later it can be "repaired") At this position the wlan should be working and the time sync shouldn't be started. This should work on both versions: your online and mine offline version.

while (statusMQTT != 1) {
   sleep(1);
 }

But i don't get the ldr to work. I now it holds a reference to an address, but i don't have a clue how to calculate the offset. I asked the Duck, but got only topics where you must know already assembler to understand it.

McPrapor commented 1 year ago

I thought 2.10.36 is available again, but looks like it's just the hack makes it believe it's running 2.10.36.

guino commented 1 year ago

@jonesMeUp there's not a lot to it:

READ data from any address (into r3):

ldr r0,[0xPOINTER_ADDRESS]
ldr r3,[r0,#0x0]

WRITE data to any address (from r3):

ldr r0,[0xPOINTER_ADDRESS]
str r3,[r0,#0x0]

In both cases POINTER_ADDRESS will be an address containing the address to read/write, so if you wanted to read/write to 0x434d1c you would have to place the bytes 1c 4d 43 00 somewhere (near the code) and call that 'somewhere' POINTER_ADDRESS. You could even take out part of a string to write those bytes. In my example above https://github.com/guino/Merkury1080P/issues/42#issuecomment-1360832460 I used 0x9c548 because it was already storing some address used by code I overwrote. There's no 'offset calculation' required for this method, just requires the 8 bytes (for the 2 instructions) + 4 bytes to store the absolute address to read/write (but has to be near the code).

So you'll need to copy all the bytes from the loop code to 0x065bc8 (assuming you have space) then you'll need some other 4 bytes (near that code) to put the address bytes 1c 4d 43 00. It could look like this:

LOOP:   01 00 a0 e3     mov        r0,#0x1
        18 de fe eb     bl         <EXTERNAL>::sleep
        a0 30 9f e5     ldr        r3,[POINTER_ADDRESS]
        00 30 93 e5     ldr        r3,[r3,#0x0]
        01 00 53 e3     cmp        r3,#0x1
        f8 ff ff 1a     bne        LOOP
        ?? ?? ?? ea     b          EXIT_LOOP
POINTER_ADDRESS:
        1c 4d 43 00
EXIT_LOOP:
       <existing code>

(notice the 'missing' add instruction since I'm using absolute address defined in the POINTER_ADDRESS memory location)

You also have the option to use a few more instructions to build the address directly:

LOOP:   01 00 a0 e3     mov    r0,#0x1
        18 de fe eb     bl     <EXTERNAL>::sleep
        1c 30 a0 e3     mov    r3,#0x1c
        4d 3c 83 e3     orr    r3,r3,#0x4d00
        43 38 83 e3     orr    r3,r3,#0x430000
        00 30 13 e5     ldr    r3,[r3,#0x0]
        01 00 53 e3     cmp    r3,#0x1
        f9 ff ff 1a     bne    LOOP

Either one should work as long as you have enough space -- chances are whatever code you're overwriting/deleting (to put your code in place) already uses some address nearby that you can use for a pointer_address making it simpler to write without adding jumps or multiple instructions (seems like 0x65ca8 is the perfect POINTER_ADDRESS for you).

guino commented 1 year ago

I thought 2.10.36 is available again, but looks like it's just the hack makes it believe it's running 2.10.36.

Yes, the hack uses a main application 2.10.36 so it reports that version to the server. I never did look into changing that since it works fine, but it could prevent us from knowing when a 2.10.36 is actually available for that device. Chances are it may come out as a different version than 2.10.36 anyway.

jonesMeUp commented 1 year ago

@guino i used your build the address directly version for my testings, worked well. I also added much nop instructions for you to give us more nice functions ;) Still no success on localtime, but added current lumi: x to the event loop. I want to use the camera to switch on a light when its dark on movement event. Currently i use a _Sun_RiseSetTimer calculation for this, but its not very accurate. I hope to find more time for my testings, now that the holidays are nearly over.

jonesMeUp commented 1 year ago

date and hwclock now shows the correct date/time, so no more 1970 as root of the streaming folder. But the video-stream still differs 1h. I will spend some more time on it, but if it tooks to much time - i will give up and live with it.

I will post my actual hack.sh and the patch file as soon as the 1h problem is fixed (or if i get lost in the fix).

guino commented 1 year ago

@jonesMeUp Nice to hear you've made progress. I recommend you try a normal boot (i.e. no SD card) to verify the video time is correct -- if it's off by 1h without the SD card then the issue isn't related to your changes (likely just some other setting).

jonesMeUp commented 1 year ago

@guino of course the problem is related to the offline patch. There are many functions that are only called when the device is online. To get the date fixed for the streaming folder i had to rewrite the IPC_APP_Sync_Utc_Time() funtion (which didn't make any sense in the offline version). The timestamp was coming from tuya server as a json string, now dd writes the timestamp into the new funtion after the time was synced.

I have already seen a possible location for the 1h problem:

[01-10 04:55:36-- TUYA Debug][gw_intf.c:4405] timezone:+01:00

The lines of the logfile are crying in my head, so i have to spend some time there.

jonesMeUp commented 1 year ago

@guino after searching for endless hours in the code, without any success, i think they are cheating. Can you please check if date and hwclock differ, on your online cam, also to the vlc time display?

guino commented 1 year ago

@jonesMeUp sorry it's been a busy few days here.

This is my doorbell (2.9.6 fw):

~ # date
Tue Jan 17 14:24:31 CST 2023
~ # hwclock
-sh: hwclock: not found
~ # /mnt/mmc01/busybox hwclock
hwclock: can't open '/dev/misc/rtc': No such file or directory
~ # ls -la /etc/TZ
-rwxr-xr-x    1 wagner   root            12 Jan 17 02:07 /etc/TZ
~ # cat /etc/TZ
CST05:00:00

This is my indoor dumb camera (2.7.6 fw):

~ # date
Tue Jan 17 14:26:38 CST 2023
~ # hwclock
-sh: hwclock: not found
~ # /mnt/mmc01/busybox hwclock
hwclock: can't open '/dev/misc/rtc': No such file or directory
~ # ls -la /etc/TZ
-rwxr-xr-x    1 wagner   root            12 Jan 17 01:04 /etc/TZ
~ # cat /etc/TZ
CST05:00:00

This is my rotating camera (2.10.36):

~ # date
Tue Jan 17 09:29:56 GMT 2023
~ # hwclock
Tue Jan 17 09:29:57 2023  0.000000 seconds
~ # ls -la /etc/TZ 
lrwxrwxrwx    1 1000     1000             7 Aug 24  2021 /etc/TZ -> /tmp/TZ
~ # ls -la /tmp/TZ
-rw-rw-rw-    1 root     root            10 Jan 17 09:27 /tmp/TZ
~ # cat /tmp/TZ
GMT+05:00

My local time was 14:24-29 when testing the above -- please notice I am on Eastern US timezone (despite it showing CST), but all my devices show the correct time on the video.

jonesMeUp commented 1 year ago

@guino so i searched many hours in my patches, but the gmt/date/hwclock "glitch" was in the original app already. After you confirmed my suspicion, i updated my post to my actual version, showing the correct time only in OSD (like the original version). https://github.com/guino/Merkury1080P/issues/42#issuecomment-1353850449

usernamepaul commented 3 months ago

Cyberduck ftp Server (192.168.xxx.xx) port 21 user: root pass:telnet