Samsung NX300: Dissecting a Hacked Firmware
I mentioned in an earlier blog post, that I'm working on the Samsung NX300(m) mirrorless cameras and trying to get some features to work. I outlined in that post a way to get unlimited movie record length. While this method seems to screw up the time remaining, recording always stops just over the 4GB file size marker on my NX300m cameras.
Furtunately someone made a hacked formware [1] for the NX300 cameras, which allows unlimted movie record times, and it seems to work fine at least on my NX300. The link [2] leads you to the download for this specific firmware.
In this blog post I'll dive into the differences of the hacked version and an official image of the latest version 1.45 of the firmware for the NX300 camera. This is gonna get technical, so grab your ARM Instruction Set Manual and join me on that journey.
A Tale of two Binary Images
It is hinted in the forum posts, that the firmware for the NX300 and the NX300M are packed differently. I already know, that Samsung shipped different software for the M-models, so I expect I cannot just copy over the hacked NX300 binary to the NX300M. However finding the differences between the original firmware and the one with unlimited video record length may give me a lead to what might be necessary for the same effect on the NX300M.
From the OpenSource-parts of the firmware of the NX300M I already know, that the binary I should be most interested in is the di-camera-app-nx300m
or similar, which is the brains of the operation, managing the software modes and configuring the drimeIV ASIC to capture a photo, i.e. read-out the sensor and create an JPEG of that readout on the SD-Card, or capture a movie with sound and encode it as H.264 in mp4-files.
Unpackung and Mounting the Firmware Images
First I need to unpack the nx300.bin
firmware images and mount the linux root-filesystem of the camera in my system. I'm using an Arch Linux, so if you want to do the same (or similar thing) on a different distribution, your packages may be called differently.
To unpack the firmware images, I wrote myself a C-program (see below), mmap
ing the header [3] of the firmware, finding the right offsets and using dd
to extract the different parts. See, the firmware image is essentially a header and then cat
ed files behind each other. The header contains the offset and size of each section in the firmware image.
The only file I'm actually interested in, is the platform.img
, which contains the whole linux filesystem. The others are some kind of loaders and probably firmware for the drime4 itself. However it is not simply a copy of an ext4-filesystem to be mounted, it is a UBIFS, which is used for flash based filesystems.
Mounting the filesystem is a bit cumbersome, so I've written myself a Makefile. First the nandsim
module is loaded, the platform.img is copied into the mtd0 device of the nandsim module, then ubi
is loaded and mtd0 is attached to the ubi-driver. Lastly the ubi-device is mounted to /mnt/ubi
, which allows us finally to view the goods inside.
mount: platform.img
echo "run as root"
modprobe nandsim cache_file=./temp_nand.dat first_id_byte=0x20 second_id_byte=0xac third_id_byte=0x00 fourth_id_byte=0x15
dd if=platform.img of=/dev/mtd0 bs=2048
modprobe ubi
ubiattach -m 0 -O 2048
-mkdir /mnt/ubi
mount -t ubifs ubi0_0 /mnt/ubi
You may need the package mtd-utils
for mounting the image.
Finding Differences
Now the real problem starts. How to find differences in the image? I already know from the opensource package, that there are loads of libraries and the di-camera-app
, which implement most of the cameras functionality. Then maybe there might be some files not present in one or the other.
So i've written myself a small, overengineered bash script md5ing all files and comparing the hashes against each other. The differences show in /etc/version.info
with an additional byte, that looks astonishingly like a 'c' after the version number, and in the di-camera-app
. The other differing files are due to a bug I didn't bother to fix, as the script does not handle spaces in the file paths well at all.
Dissecting the Disassembly
Ok, we've essentially found out, that the main difference seems to be in the di-camera-app
, which is more or less expected, since this binary handles all of the ARM-side software of the camera. So, I've run arm-none-eabi-objdump
on them and took a diff
(for the lulz I repeated that with forced thumb-mode, which did not go well, so I can be sure, that this code seems to be regular ARM code).
2c2
< di-camera-app-hacked: file format elf32-littlearm
---
> di-camera-app-original: file format elf32-littlearm
381052c381052
< 177670: e3e03102 mvn r3, #-2147483648 ; 0x80000000
---
> 177670: e3a03000 mov r3, #0
443109c443109
< 1b3840: e3e03102 mvn r3, #-2147483648 ; 0x80000000
---
> 1b3840: e3003706 movw r3, #1798 ; 0x706
Aha! Two differences, about 4 changed bytes, that makes all the difference. But why? Well, let's look at the disassembly of the unofficial firmware, especially around where I found the differences:
00177660 <_Z28UI_Get_Storage_File_Max_Sizev@@Base>:
177660: e52db004 push {fp} ; (str fp, [sp, #-4]!)
177664: e28db000 add fp, sp, #0
177668: e24dd00c sub sp, sp, #12
17766c: e3e02000 mvn r2, #0
> 177670: e3e03102 mvn r3, #-2147483648 ; 0x80000000
177674: e14b20fc strd r2, [fp, #-12]
177678: e14b20dc ldrd r2, [fp, #-12]
17767c: e1a00002 mov r0, r2
177680: e1a01003 mov r1, r3
177684: e28bd000 add sp, fp, #0
177688: e8bd0800 ldmfd sp!, {fp}
17768c: e12fff1e bx lr
I've marked the changed line. At first there was an mov r3, #0
which would have set the register r3
to the value of 0, now it's a move negative mvn r3, #0x80000000
. This instruction bitwise negates the source operand and sets the destination with the value, i.e. making r3 the largest possible signed 32 bit value 0x7fffffff
.
From what I can get, this seems to be intializing one of the two return parameters to the maximal value, so make the calling code think, that the maximal file size of the file system is essentially unlimited. However, the code looks somewhat weird. strd
and ldrd
are store and load-operations on double-words, so I assume that this code means r2
and r3
are stored onto the newly created stack and read back from it. It looks to me, that the Samsung engineers forgot to enable compiler optimizations, as no normal not-braindead-compiler wouldn't keep these values just in the registers.
A bit concerning is the bx
instruction at the end, which is a branch (to the Link Register lr
, which is the ARM version of a return), but with changing the instruction set. So whatever it returns to should be Thumb code, if I understand that correctly. Maybe I'll have to do more research on that.
Well, let's get to the second change. I'll abbreviate it here, but I'll put the whole file in the appendix.
001b3584 <_Z25UI_Get_Movie_Remaian_Timev@@Base>:
...
1b3610: ebff0fff bl 177614 <_Z25UI_Get_Storage_Free_Spacev@@Base>
1b3614: e1a02000 mov r2, r0
1b3618: e1a03001 mov r3, r1
1b361c: e14b26fc strd r2, [fp, #-108] ; 0xffffff94
> 1b3620: ebff100e bl 177660 <_Z28UI_Get_Storage_File_Max_Sizev@@Base>
1b3624: e1a02000 mov r2, r0
1b3628: e1a03001 mov r3, r1
1b362c: e14b27f4 strd r2, [fp, #-116] ; 0xffffff8c
1b3630: e3a02000 mov r2, #0
1b3634: e3a03000 mov r3, #0
1b3638: e14b22f4 strd r2, [fp, #-36] ; 0xffffffdc
1b363c: e3a03000 mov r3, #0
1b3640: e50b3028 str r3, [fp, #-40] ; 0xffffffd8
1b3644: e3a00053 mov r0, #83 ; 0x53
1b3648: ebfed3f2 bl 168618 <_Z12UI_Get_Value14eUI_VALUE_ITEM@@Base>
1b364c: e1a03000 mov r3, r0
1b3650: e50b3078 str r3, [fp, #-120] ; 0xffffff88
1b3654: e3a00050 mov r0, #80 ; 0x50
1b3658: ebfed3ee bl 168618 <_Z12UI_Get_Value14eUI_VALUE_ITEM@@Base>
1b365c: e1a03000 mov r3, r0
1b3660: e50b307c str r3, [fp, #-124] ; 0xffffff84
1b3664: e51b007c ldr r0, [fp, #-124] ; 0xffffff84
1b3668: e3a01000 mov r1, #0
1b366c: eb001748 bl 1b9394 <_Z22UI_Set_Attr_Movie_Size18eUI_CAP_MOVIE_SIZE@@Base+0x1100>
1b3670: e1a03000 mov r3, r0
1b3674: e50b3060 str r3, [fp, #-96] ; 0xffffffa0
1b3678: e51b007c ldr r0, [fp, #-124] ; 0xffffff84
1b367c: ebffff3c bl 1b3374 <_Z21UI_Get_Video_Bit_Rate18eUI_CAP_MOVIE_SIZE@@Base>
1b3680: e1a03000 mov r3, r0
1b3684: e50b3058 str r3, [fp, #-88] ; 0xffffffa8
1b3688: e24b2084 sub r2, fp, #132 ; 0x84
1b368c: e24b3088 sub r3, fp, #136 ; 0x88
1b3690: e1a00002 mov r0, r2
1b3694: e1a01003 mov r1, r3
1b3698: ebffff98 bl 1b3500 <_Z21UI_Get_Audio_Bit_RatePiS_@@Base>
1b369c: e51b2068 ldr r2, [fp, #-104] ; 0xffffff98
1b36a0: e51b3070 ldr r3, [fp, #-112] ; 0xffffff90
1b36a4: e1520003 cmp r2, r3
...
1b37e8: ebfadace bl 6a328 <mm_util_movie_record_time@plt>
1b37ec: e1a03000 mov r3, r0
1b37f0: e50b3018 str r3, [fp, #-24] ; 0xffffffe8
1b37f4: e51b3078 ldr r3, [fp, #-120] ; 0xffffff88
1b37f8: e3530000 cmp r3, #0
1b37fc: 1a000006 bne 1b381c <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x298>
1b3800: e51b3018 ldr r3, [fp, #-24] ; 0xffffffe8
1b3804: e2832003 add r2, r3, #3
1b3808: e3530000 cmp r3, #0
1b380c: b1a03002 movlt r3, r2
1b3810: e1a03143 asr r3, r3, #2
1b3814: e50b3018 str r3, [fp, #-24] ; 0xffffffe8
1b3818: ea000007 b 1b383c <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x2b8>
1b381c: e51b3078 ldr r3, [fp, #-120] ; 0xffffff88
1b3820: e3530001 cmp r3, #1
1b3824: 1a000004 bne 1b383c <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x2b8>
1b3828: e51b3018 ldr r3, [fp, #-24] ; 0xffffffe8
1b382c: e1a02fa3 lsr r2, r3, #31
1b3830: e0823003 add r3, r2, r3
1b3834: e1a030c3 asr r3, r3, #1
1b3838: e50b3018 str r3, [fp, #-24] ; 0xffffffe8
1b383c: e51b2018 ldr r2, [fp, #-24] ; 0xffffffe8
> 1b3840: e3e03102 mvn r3, #-2147483648 ; 0x80000000
1b3844: e1520003 cmp r2, r3
1b3848: da000002 ble 1b3858 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x2d4>
1b384c: e3003707 movw r3, #1799 ; 0x707
1b3850: e50b301c str r3, [fp, #-28] ; 0xffffffe4
1b3854: ea000001 b 1b3860 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x2dc>
1b3858: e51b3018 ldr r3, [fp, #-24] ; 0xffffffe8
1b385c: e50b301c str r3, [fp, #-28] ; 0xffffffe4
1b3860: e51b307c ldr r3, [fp, #-124] ; 0xffffff84
1b3864: e3530007 cmp r3, #7
...
This one is a bit bigger. First, we find the only call-site of the StorageMax function we saw our first change in. The return values are stored in r2
and r3
and placed on the stack. I'd assume, that there is a cmp
(compare) statement with these values later on, which would stop the recording, when the file size limit is hit.
Then later on, near the middle of the function, but at the end of the excerpt, we find our second change. Normally we'd write the value of 1798 into register r3
, but we want to write signed integer max. You know 1798 looks an awful lot like the maximal amount of seconds a video can be. And sure enough, when we divide 60 from it, we get 29.9 minutes, which is the maximal time for 1080p30 videos. In the 1080p60 video mode, the time is reduced to 21 minutes and a few seconds, because the file size exceeds the 4G limit by the FAT-filesystem. However the SD cards are formatted to exfat in the NX300M which allows for nearly unlimited file sized.
One thing to note here is, that there is a function UI::GetVideoBitRate in the function. One can savely assume, that this function may be used for communication with the drime4 ASIC to set the correct bitrate and quality setting for the movie recording. That may of course also be a red hering.
Conclusion
So, from what I can understand, the breaking points on the NX300 were the maximal file size of the filesystem. I did not see where the function would get the information about the file system on the SD card, so this may or may not be breakable by using an ext2-formatted card and a cross compiled ext2-kernel module [4].
The second change was to eliminate the hard limit to 30 minutes of movie recording. I haven't investigated that close enough, but maybe there is a check for the system parameter, where we could disable the recording limit.
References
[1] https://www.dpreview.com/forums/post/56754944
[2] https://mega.nz/file/RAJCiIIZ#LappfCn1QSppxx9eu49DvTqS9GhvSYA_Edqr6S6o2ZA
[3] https://sites.google.com/site/nxcryptophotography/diy-firmware
[4] https://lemmster.de/cross-compile-kernel-module-samsung-nx300-ubnut-14.04.html
Appendix
extractor.c
// CC-BY-NC-SA Stefan Naumann
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
struct meta {
uint32_t size;
uint32_t crc;
uint32_t start;
uint32_t unknown; // maybe address for flash?
};
#define PRINT_META(name,x) printf("%s { \n\tsize : 0x%08lx\n\tcrc : 0x%08lx\n\tstart: 0x%08lx\n\tunknown: %lx\n};\n", name, x.size, x.crc, x.start, x.unknown);
struct header {
uint8_t stuff[0x40];
struct meta vimage;
struct meta d4ipl;
struct meta d4pnlbl;
struct meta uimage;
struct meta platform;
struct meta pcache;
};
const char* name[] = {
"vImage",
"D4_IPL",
"D4_PNLBL",
"uImage",
"platform",
"pcache"
};
const char* fname[] = {
"vImage",
"D4_IPL.bin",
"D4_PNLBL.bin",
"uImage",
"platform.img",
"pcache.list"
};
static_assert ( sizeof(struct meta) == 4*4 );
static_assert ( sizeof(struct header) == 0xa0 );
bool checkCRC ( const char* filename, uint32_t crc ) {
// why bother?
}
int ddout ( struct meta* m, const char* inname, const char* filename ) {
assert ( strlen(filename) < 17 );
assert ( strlen(inname) < 197 );
int pid = fork();
char skip[20]={0}, count[20]={0}, iff[200]={0}, off[20]={0}, bs[20]="bs=1";
if ( pid < 0 ) {
return ( errno != 0 ? errno : EINVAL );
}
if ( pid == 0 ) {
int bsi = 0;
while ( m->size % (1 << bsi) == 0 && bsi < 32 ) {
bsi++;
}
bsi--;
if (bsi >= 32) {
bsi = 0;
}
snprintf ( skip, 20, "skip=%ld", m->start );
snprintf ( count, 20, "count=%ld", m->size );
snprintf ( iff, 200, "if=%s", inname );
snprintf ( off, 20, "of=%s", filename );
snprintf ( bs, 20, "bs=%d", 1 );
printf ( "%s %s %s %s %s %s status=progress\n", "dd", skip, count, iff, off, bs );
execlp ( "dd", "dd", skip, count, iff, off, bs, "status=progress", NULL );
exit(EINVAL);
}
int rc;
waitpid ( pid, &rc, 0 );
return WEXITSTATUS(rc);
}
int main ( int argc, char** argv ) {
if ( argc != 2 ) {
printf ( "usage: %s {filename}\n", argv[0] );
return EINVAL;
}
errno = 0;
int fd = open ( argv[1], O_RDONLY );
if ( fd < 0 ) {
printf ("open: %s\n", strerror ( errno ) );
return errno;
}
struct header* hdr = (struct header*) mmap ( NULL, 0xa0, PROT_READ, MAP_PRIVATE, fd, 0 );
close ( fd );
if ( (void*)hdr == (void*)MAP_FAILED ) {
printf ("mmap: %s\n", strerror ( errno ) );
return errno;
}
struct meta* m = &hdr->vimage;
for ( int i = 0; i<6; i++ ) {
PRINT_META ( name[i], m[i] );
ddout ( &m[i], argv[1], fname[i] );
}
munmap ( hdr, 0xa0 );
return 0;
}
diff.sh
#!/bin/bash
# CC-BY-SA-NC by Stefan Naumann
NORMAL=32
WARN=31
CHECK=34
## "simple" logging function using asci escape colors and output files
function log () {
level=${2:-${NORMAL}}
output=${3:-"/dev/stdout"}
echo -e "\033[${level};1m> $1\033[0m" >> $output
}
log "Usage: diff.sh <orig> <hacked> <outfile>"
log "Tool to find diffrences in two folders, comparing all files"
h=${2:-"hacked"}
o=${1:-"original"}
outfile={3:-"diffout"}
## Use find and md5sum to get all the files, scan their contents
log "Scanning directory $h"
hmd5=$(find $h -type f -exec md5sum {} + | sort -k 2)
log "Scanning directory $o"
omd5=$(find $o -type f -exec md5sum {} + | sort -k 2)
## vars for progress output
totallines=$(echo "$hmd5" | wc | awk '{print $1}')
i=0
last=0
log "Diffing ($totallines files)"
## for all files
while IFS= read -r line; do
## remove prefix from the hacked filename
hfile=$(echo "$line" | awk '{print $2}')
hfile=${hfile#"$h"}
## find the corresponding file in the original filesystem
oline=$(echo "$omd5" | grep "${hfile}")
nlines=$(echo "$oline" | wc | awk '{print $1}')
stat=0
## grep may have found 0, 1 (perfect!) or more equivalents (as I can't search for exact matches)
if [ $nlines -eq 0 ]; then
log "Could not find file $hfile" WARN
continue
elif [ $nlines -gt 1 ]; then
## if it found >1 equivalent, we have to search ourselves
while IFS= read -r l2; do
f=$(echo "$l2" | awk '{print $2}')
f=${f#"$o"}
if [ "$f" = "$hfile" ]; then
oline="$l2"
stat=1
break;
fi
done <<< "$oline"
else
## exactly one -> perfect
stat=1
fi
## oline="" if grep did not find anything
## stat=0 if grep did not find anything or it found >1 file and we did not
## find anything ourselves
if [ "$oline" = "" ] || [ $stat -eq 0 ]; then
log "Did not find file $hfile" WARN
else
hsum=$(echo "$line" | awk '{print $1}')
osum=$(echo "$oline" | awk '{print $1}')
# check the checksum of the original and hacked file
if [ "$osum" = "$hsum" ]; then
:
else
log "Checksums did not check out on '$hfile'" $CHECK $outfile
fi
fi
## progress output
i=$((i+1))
next=$((last+250))
if [ $i -gt $next ]; then
log "progress ($i/$totallines files)"
last=$next;
fi
done <<< "$hmd5"
UI::GetMovieRemaianTime
001b3584 <_Z25UI_Get_Movie_Remaian_Timev@@Base>:
1b3584: e92d48f0 push {r4, r5, r6, r7, fp, lr}
1b3588: e28db014 add fp, sp, #20
1b358c: e24dd088 sub sp, sp, #136 ; 0x88
1b3590: e3a03b01 mov r3, #1024 ; 0x400
1b3594: e50b3030 str r3, [fp, #-48] ; 0xffffffd0
1b3598: e3003707 movw r3, #1799 ; 0x707
1b359c: e50b3034 str r3, [fp, #-52] ; 0xffffffcc
1b35a0: e3a0301e mov r3, #30
1b35a4: e50b3038 str r3, [fp, #-56] ; 0xffffffc8
1b35a8: e3a03096 mov r3, #150 ; 0x96
1b35ac: e50b303c str r3, [fp, #-60] ; 0xffffffc4
1b35b0: e3a03f4b mov r3, #300 ; 0x12c
1b35b4: e50b3040 str r3, [fp, #-64] ; 0xffffffc0
1b35b8: e3a03f96 mov r3, #600 ; 0x258
1b35bc: e50b3044 str r3, [fp, #-68] ; 0xffffffbc
1b35c0: e3a0300f mov r3, #15
1b35c4: e50b3048 str r3, [fp, #-72] ; 0xffffffb8
1b35c8: e3a03007 mov r3, #7
1b35cc: e50b304c str r3, [fp, #-76] ; 0xffffffb4
1b35d0: e3e03102 mvn r3, #-2147483648 ; 0x80000000
1b35d4: e50b3050 str r3, [fp, #-80] ; 0xffffffb0
1b35d8: e3a03000 mov r3, #0
1b35dc: e50b3080 str r3, [fp, #-128] ; 0xffffff80
1b35e0: e3a03000 mov r3, #0
1b35e4: e50b3054 str r3, [fp, #-84] ; 0xffffffac
1b35e8: e3a03000 mov r3, #0
1b35ec: e50b3058 str r3, [fp, #-88] ; 0xffffffa8
1b35f0: e3a03000 mov r3, #0
1b35f4: e50b3018 str r3, [fp, #-24] ; 0xffffffe8
1b35f8: e3a03000 mov r3, #0
1b35fc: e50b301c str r3, [fp, #-28] ; 0xffffffe4
1b3600: e3a03000 mov r3, #0
1b3604: e50b305c str r3, [fp, #-92] ; 0xffffffa4
1b3608: e3a03000 mov r3, #0
1b360c: e50b3060 str r3, [fp, #-96] ; 0xffffffa0
1b3610: ebff0fff bl 177614 <_Z25UI_Get_Storage_Free_Spacev@@Base>
1b3614: e1a02000 mov r2, r0
1b3618: e1a03001 mov r3, r1
1b361c: e14b26fc strd r2, [fp, #-108] ; 0xffffff94
> 1b3620: ebff100e bl 177660 <_Z28UI_Get_Storage_File_Max_Sizev@@Base>
1b3624: e1a02000 mov r2, r0
1b3628: e1a03001 mov r3, r1
1b362c: e14b27f4 strd r2, [fp, #-116] ; 0xffffff8c
1b3630: e3a02000 mov r2, #0
1b3634: e3a03000 mov r3, #0
1b3638: e14b22f4 strd r2, [fp, #-36] ; 0xffffffdc
1b363c: e3a03000 mov r3, #0
1b3640: e50b3028 str r3, [fp, #-40] ; 0xffffffd8
1b3644: e3a00053 mov r0, #83 ; 0x53
1b3648: ebfed3f2 bl 168618 <_Z12UI_Get_Value14eUI_VALUE_ITEM@@Base>
1b364c: e1a03000 mov r3, r0
1b3650: e50b3078 str r3, [fp, #-120] ; 0xffffff88
1b3654: e3a00050 mov r0, #80 ; 0x50
1b3658: ebfed3ee bl 168618 <_Z12UI_Get_Value14eUI_VALUE_ITEM@@Base>
1b365c: e1a03000 mov r3, r0
1b3660: e50b307c str r3, [fp, #-124] ; 0xffffff84
1b3664: e51b007c ldr r0, [fp, #-124] ; 0xffffff84
1b3668: e3a01000 mov r1, #0
1b366c: eb001748 bl 1b9394 <_Z22UI_Set_Attr_Movie_Size18eUI_CAP_MOVIE_SIZE@@Base+0x1100>
1b3670: e1a03000 mov r3, r0
1b3674: e50b3060 str r3, [fp, #-96] ; 0xffffffa0
1b3678: e51b007c ldr r0, [fp, #-124] ; 0xffffff84
1b367c: ebffff3c bl 1b3374 <_Z21UI_Get_Video_Bit_Rate18eUI_CAP_MOVIE_SIZE@@Base>
1b3680: e1a03000 mov r3, r0
1b3684: e50b3058 str r3, [fp, #-88] ; 0xffffffa8
1b3688: e24b2084 sub r2, fp, #132 ; 0x84
1b368c: e24b3088 sub r3, fp, #136 ; 0x88
1b3690: e1a00002 mov r0, r2
1b3694: e1a01003 mov r1, r3
1b3698: ebffff98 bl 1b3500 <_Z21UI_Get_Audio_Bit_RatePiS_@@Base>
1b369c: e51b2068 ldr r2, [fp, #-104] ; 0xffffff98
1b36a0: e51b3070 ldr r3, [fp, #-112] ; 0xffffff90
1b36a4: e1520003 cmp r2, r3
1b36a8: 8a00000b bhi 1b36dc <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x158>
1b36ac: e51b2068 ldr r2, [fp, #-104] ; 0xffffff98
1b36b0: e51b3070 ldr r3, [fp, #-112] ; 0xffffff90
1b36b4: e1520003 cmp r2, r3
1b36b8: 1a000011 bne 1b3704 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x180>
1b36bc: e51b206c ldr r2, [fp, #-108] ; 0xffffff94
1b36c0: e51b3074 ldr r3, [fp, #-116] ; 0xffffff8c
1b36c4: e1520003 cmp r2, r3
1b36c8: 8a000003 bhi 1b36dc <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x158>
1b36cc: e51b206c ldr r2, [fp, #-108] ; 0xffffff94
1b36d0: e51b3074 ldr r3, [fp, #-116] ; 0xffffff8c
1b36d4: e1520003 cmp r2, r3
1b36d8: ea000009 b 1b3704 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x180>
1b36dc: e14b27d4 ldrd r2, [fp, #-116] ; 0xffffff8c
1b36e0: e14b22f4 strd r2, [fp, #-36] ; 0xffffffdc
1b36e4: e14b27d4 ldrd r2, [fp, #-116] ; 0xffffff8c
1b36e8: e1a01b03 lsl r1, r3, #22
1b36ec: e1a06522 lsr r6, r2, #10
1b36f0: e1816006 orr r6, r1, r6
1b36f4: e1a07523 lsr r7, r3, #10
1b36f8: e1a03006 mov r3, r6
1b36fc: e50b3028 str r3, [fp, #-40] ; 0xffffffd8
1b3700: ea000008 b 1b3728 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x1a4>
1b3704: e14b26dc ldrd r2, [fp, #-108] ; 0xffffff94
1b3708: e14b22f4 strd r2, [fp, #-36] ; 0xffffffdc
1b370c: e14b26dc ldrd r2, [fp, #-108] ; 0xffffff94
1b3710: e1a01b03 lsl r1, r3, #22
1b3714: e1a04522 lsr r4, r2, #10
1b3718: e1814004 orr r4, r1, r4
1b371c: e1a05523 lsr r5, r3, #10
1b3720: e1a03004 mov r3, r4
1b3724: e50b3028 str r3, [fp, #-40] ; 0xffffffd8
1b3728: e3a03000 mov r3, #0
1b372c: e50b302c str r3, [fp, #-44] ; 0xffffffd4
1b3730: e3a00030 mov r0, #48 ; 0x30
1b3734: eb012277 bl 1fc118 <_Z12UI_Get_State14eUI_STATE_ITEM@@Base>
1b3738: e1a03000 mov r3, r0
1b373c: e3530001 cmp r3, #1
1b3740: 13a03000 movne r3, #0
1b3744: 03a03001 moveq r3, #1
1b3748: e6ef3073 uxtb r3, r3
1b374c: e3530000 cmp r3, #0
1b3750: 0a00000d beq 1b378c <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x208>
1b3754: e3a000c3 mov r0, #195 ; 0xc3
1b3758: ebfed3ae bl 168618 <_Z12UI_Get_Value14eUI_VALUE_ITEM@@Base>
1b375c: e1a03000 mov r3, r0
1b3760: e3530001 cmp r3, #1
1b3764: 13a03000 movne r3, #0
1b3768: 03a03001 moveq r3, #1
1b376c: e6ef3073 uxtb r3, r3
1b3770: e3530000 cmp r3, #0
1b3774: 0a000002 beq 1b3784 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x200>
1b3778: e3a03004 mov r3, #4
1b377c: e50b302c str r3, [fp, #-44] ; 0xffffffd4
1b3780: ea000001 b 1b378c <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x208>
1b3784: e3a03001 mov r3, #1
1b3788: e50b302c str r3, [fp, #-44] ; 0xffffffd4
1b378c: e14b26dc ldrd r2, [fp, #-108] ; 0xffffff94
1b3790: e51bc088 ldr ip, [fp, #-136] ; 0xffffff78
1b3794: e51b1060 ldr r1, [fp, #-96] ; 0xffffffa0
1b3798: e58d1000 str r1, [sp]
1b379c: e51b102c ldr r1, [fp, #-44] ; 0xffffffd4
1b37a0: e58d1004 str r1, [sp, #4]
1b37a4: e1a00002 mov r0, r2
1b37a8: e1a01003 mov r1, r3
1b37ac: e51b2058 ldr r2, [fp, #-88] ; 0xffffffa8
1b37b0: e1a0300c mov r3, ip
1b37b4: ebfadadb bl 6a328 <mm_util_movie_record_time@plt>
1b37b8: e1a03000 mov r3, r0
1b37bc: e50b305c str r3, [fp, #-92] ; 0xffffffa4
1b37c0: e14b22d4 ldrd r2, [fp, #-36] ; 0xffffffdc
1b37c4: e51bc088 ldr ip, [fp, #-136] ; 0xffffff78
1b37c8: e51b1060 ldr r1, [fp, #-96] ; 0xffffffa0
1b37cc: e58d1000 str r1, [sp]
1b37d0: e51b102c ldr r1, [fp, #-44] ; 0xffffffd4
1b37d4: e58d1004 str r1, [sp, #4]
1b37d8: e1a00002 mov r0, r2
1b37dc: e1a01003 mov r1, r3
1b37e0: e51b2058 ldr r2, [fp, #-88] ; 0xffffffa8
1b37e4: e1a0300c mov r3, ip
1b37e8: ebfadace bl 6a328 <mm_util_movie_record_time@plt>
1b37ec: e1a03000 mov r3, r0
1b37f0: e50b3018 str r3, [fp, #-24] ; 0xffffffe8
1b37f4: e51b3078 ldr r3, [fp, #-120] ; 0xffffff88
1b37f8: e3530000 cmp r3, #0
1b37fc: 1a000006 bne 1b381c <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x298>
1b3800: e51b3018 ldr r3, [fp, #-24] ; 0xffffffe8
1b3804: e2832003 add r2, r3, #3
1b3808: e3530000 cmp r3, #0
1b380c: b1a03002 movlt r3, r2
1b3810: e1a03143 asr r3, r3, #2
1b3814: e50b3018 str r3, [fp, #-24] ; 0xffffffe8
1b3818: ea000007 b 1b383c <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x2b8>
1b381c: e51b3078 ldr r3, [fp, #-120] ; 0xffffff88
1b3820: e3530001 cmp r3, #1
1b3824: 1a000004 bne 1b383c <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x2b8>
1b3828: e51b3018 ldr r3, [fp, #-24] ; 0xffffffe8
1b382c: e1a02fa3 lsr r2, r3, #31
1b3830: e0823003 add r3, r2, r3
1b3834: e1a030c3 asr r3, r3, #1
1b3838: e50b3018 str r3, [fp, #-24] ; 0xffffffe8
1b383c: e51b2018 ldr r2, [fp, #-24] ; 0xffffffe8
> 1b3840: e3e03102 mvn r3, #-2147483648 ; 0x80000000
1b3844: e1520003 cmp r2, r3
1b3848: da000002 ble 1b3858 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x2d4>
1b384c: e3003707 movw r3, #1799 ; 0x707
1b3850: e50b301c str r3, [fp, #-28] ; 0xffffffe4
1b3854: ea000001 b 1b3860 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x2dc>
1b3858: e51b3018 ldr r3, [fp, #-24] ; 0xffffffe8
1b385c: e50b301c str r3, [fp, #-28] ; 0xffffffe4
1b3860: e51b307c ldr r3, [fp, #-124] ; 0xffffff84
1b3864: e3530007 cmp r3, #7
1b3868: 1a000039 bne 1b3954 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x3d0>
1b386c: e51b3078 ldr r3, [fp, #-120] ; 0xffffff88
1b3870: e3530003 cmp r3, #3
1b3874: 1a000005 bne 1b3890 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x30c>
1b3878: e51b3018 ldr r3, [fp, #-24] ; 0xffffffe8
1b387c: e3530095 cmp r3, #149 ; 0x95
1b3880: da000002 ble 1b3890 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x30c>
1b3884: e3a03096 mov r3, #150 ; 0x96
1b3888: e50b301c str r3, [fp, #-28] ; 0xffffffe4
1b388c: ea000030 b 1b3954 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x3d0>
1b3890: e51b3078 ldr r3, [fp, #-120] ; 0xffffff88
1b3894: e3530004 cmp r3, #4
1b3898: 1a000006 bne 1b38b8 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x334>
1b389c: e51b2018 ldr r2, [fp, #-24] ; 0xffffffe8
1b38a0: e300312b movw r3, #299 ; 0x12b
1b38a4: e1520003 cmp r2, r3
1b38a8: da000002 ble 1b38b8 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x334>
1b38ac: e3a03f4b mov r3, #300 ; 0x12c
1b38b0: e50b301c str r3, [fp, #-28] ; 0xffffffe4
1b38b4: ea000026 b 1b3954 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x3d0>
1b38b8: e51b3078 ldr r3, [fp, #-120] ; 0xffffff88
1b38bc: e3530005 cmp r3, #5
1b38c0: 1a000006 bne 1b38e0 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x35c>
1b38c4: e51b2018 ldr r2, [fp, #-24] ; 0xffffffe8
1b38c8: e3003257 movw r3, #599 ; 0x257
1b38cc: e1520003 cmp r2, r3
1b38d0: da000002 ble 1b38e0 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x35c>
1b38d4: e3a03f96 mov r3, #600 ; 0x258
1b38d8: e50b301c str r3, [fp, #-28] ; 0xffffffe4
1b38dc: ea00001c b 1b3954 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x3d0>
1b38e0: e51b3078 ldr r3, [fp, #-120] ; 0xffffff88
1b38e4: e3530000 cmp r3, #0
1b38e8: 1a000005 bne 1b3904 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x380>
1b38ec: e51b3018 ldr r3, [fp, #-24] ; 0xffffffe8
1b38f0: e3530006 cmp r3, #6
1b38f4: da000002 ble 1b3904 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x380>
1b38f8: e3a03007 mov r3, #7
1b38fc: e50b301c str r3, [fp, #-28] ; 0xffffffe4
1b3900: ea000013 b 1b3954 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x3d0>
1b3904: e51b3078 ldr r3, [fp, #-120] ; 0xffffff88
1b3908: e3530001 cmp r3, #1
1b390c: 1a000005 bne 1b3928 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x3a4>
1b3910: e51b3018 ldr r3, [fp, #-24] ; 0xffffffe8
1b3914: e353000e cmp r3, #14
1b3918: da000002 ble 1b3928 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x3a4>
1b391c: e3a0300f mov r3, #15
1b3920: e50b301c str r3, [fp, #-28] ; 0xffffffe4
1b3924: ea00000a b 1b3954 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x3d0>
1b3928: e51b3078 ldr r3, [fp, #-120] ; 0xffffff88
1b392c: e3530002 cmp r3, #2
1b3930: 1a000005 bne 1b394c <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x3c8>
1b3934: e51b3018 ldr r3, [fp, #-24] ; 0xffffffe8
1b3938: e353001d cmp r3, #29
1b393c: da000002 ble 1b394c <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x3c8>
1b3940: e3a0301e mov r3, #30
1b3944: e50b301c str r3, [fp, #-28] ; 0xffffffe4
1b3948: ea000001 b 1b3954 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x3d0>
1b394c: e51b3018 ldr r3, [fp, #-24] ; 0xffffffe8
1b3950: e50b301c str r3, [fp, #-28] ; 0xffffffe4
1b3954: e3000583 movw r0, #1411 ; 0x583
1b3958: ebfed32e bl 168618 <_Z12UI_Get_Value14eUI_VALUE_ITEM@@Base>
1b395c: e1a03000 mov r3, r0
1b3960: e3530000 cmp r3, #0
1b3964: 1a000004 bne 1b397c <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x3f8>
1b3968: e3a00e3f mov r0, #1008 ; 0x3f0
1b396c: ebfed329 bl 168618 <_Z12UI_Get_Value14eUI_VALUE_ITEM@@Base>
1b3970: e1a03000 mov r3, r0
1b3974: e353001f cmp r3, #31
1b3978: 1a000001 bne 1b3984 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x400>
1b397c: e3a03001 mov r3, #1
1b3980: ea000000 b 1b3988 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x404>
1b3984: e3a03000 mov r3, #0
1b3988: e3530000 cmp r3, #0
1b398c: 0a000001 beq 1b3998 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x414>
1b3990: e3e03102 mvn r3, #-2147483648 ; 0x80000000
1b3994: e50b301c str r3, [fp, #-28] ; 0xffffffe4
1b3998: e3a0007c mov r0, #124 ; 0x7c
1b399c: e51b101c ldr r1, [fp, #-28] ; 0xffffffe4
1b39a0: ebfed36c bl 168758 <_Z12UI_Set_Value14eUI_VALUE_ITEMi@@Base>
1b39a4: e3003048 movw r3, #72 ; 0x48
1b39a8: e340304e movt r3, #78 ; 0x4e
1b39ac: e5931000 ldr r1, [r3]
1b39b0: e24b2080 sub r2, fp, #128 ; 0x80
1b39b4: e30a3790 movw r3, #42896 ; 0xa790
1b39b8: e3403026 movt r3, #38 ; 0x26
1b39bc: e58d3000 str r3, [sp]
1b39c0: e51b301c ldr r3, [fp, #-28] ; 0xffffffe4
1b39c4: e58d3004 str r3, [sp, #4]
1b39c8: e3a03000 mov r3, #0
1b39cc: e58d3008 str r3, [sp, #8]
1b39d0: e1a00001 mov r0, r1
1b39d4: e1a01002 mov r1, r2
1b39d8: e30a2780 movw r2, #42880 ; 0xa780
1b39dc: e3402026 movt r2, #38 ; 0x26
1b39e0: e51b3028 ldr r3, [fp, #-40] ; 0xffffffd8
1b39e4: ebfadf8c bl 6b81c <mm_camcorder_set_attributes@plt>
1b39e8: e1a03000 mov r3, r0
1b39ec: e50b3054 str r3, [fp, #-84] ; 0xffffffac
1b39f0: e51b3054 ldr r3, [fp, #-84] ; 0xffffffac
1b39f4: e3530000 cmp r3, #0
1b39f8: 0a000012 beq 1b3a48 <_Z25UI_Get_Movie_Remaian_Timev@@Base+0x4c4>
1b39fc: e51b2080 ldr r2, [fp, #-128] ; 0xffffff80
1b3a00: e30a37a4 movw r3, #42916 ; 0xa7a4
1b3a04: e3403026 movt r3, #38 ; 0x26
1b3a08: e58d3000 str r3, [sp]
1b3a0c: e51b3054 ldr r3, [fp, #-84] ; 0xffffffac
1b3a10: e58d3004 str r3, [sp, #4]
1b3a14: e58d2008 str r2, [sp, #8]
1b3a18: e30a0760 movw r0, #42848 ; 0xa760
1b3a1c: e3400026 movt r0, #38 ; 0x26
1b3a20: e30b1744 movw r1, #46916 ; 0xb744
1b3a24: e3401026 movt r1, #38 ; 0x26
1b3a28: e3002251 movw r2, #593 ; 0x251
1b3a2c: e3a03000 mov r3, #0
1b3a30: ebfae4ad bl 6ccec <slpcam_print_log@plt>
1b3a34: e51b3080 ldr r3, [fp, #-128] ; 0xffffff80
1b3a38: e1a00003 mov r0, r3
1b3a3c: ebfade50 bl 6b384 <free@plt>
1b3a40: e3a03000 mov r3, #0
1b3a44: e50b3080 str r3, [fp, #-128] ; 0xffffff80
1b3a48: e51b305c ldr r3, [fp, #-92] ; 0xffffffa4
1b3a4c: e1a00003 mov r0, r3
1b3a50: e24bd014 sub sp, fp, #20
1b3a54: e8bd88f0 pop {r4, r5, r6, r7, fp, pc}