mayanklahiri / easyexif Goto Github PK
View Code? Open in Web Editor NEWTiny ISO-compliant C++ EXIF parsing library, third-party dependency free.
License: Other
Tiny ISO-compliant C++ EXIF parsing library, third-party dependency free.
License: Other
Thanks for giving us easyexif, it works great and is very lightweight and accessible. For me it therefore surpasses all of the existing libraries.
However, have you ever considered the possibility of modifying EXIF data of an existing image? In particular I would like to be able to modify the date-time information (for the case that I forgot to update the time settings of my camera).
I try the valgrind check with one demo image and got the following errors:
valgrind --leak-check=full ./demo test-images/short-ascii-II.jpg
==84545== Memcheck, a memory error detector
==84545== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==84545== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==84545== Command: ./demo test-images/short-ascii-II.jpg
==84545==
--84545-- run: /usr/bin/dsymutil "./demo"
warning: no debug symbols in executable (-arch x86_64)
Camera make : XIAOMI
Camera model : MI3
Software :
Bits per sample : 0
Image width : 4208
Image height : 3120
Image description :
Image orientation : 1
Image copyright :
Image date/time : 2015:02:28 17:10:49
Original date/time : 2015:02:28 17:10:49
Digitize date/time : 2015:02:28 17:10:49
Subsecond time :
Exposure time : 1/20 s
F-stop : f/2.2
ISO speed : 250
Subject distance : 0.000000 m
Exposure bias : 0.000000 EV
Flash used? : 1
Metering mode : 2
Lens focal length : 3.510000 mm
35mm focal length : 0 mm
GPS Latitude : 0.000000 deg (0.000000 deg, 0.000000 min, 0.000000 sec ?)
GPS Longitude : 0.000000 deg (0.000000 deg, 0.000000 min, 0.000000 sec ?)
GPS Altitude : 0.000000 m
GPS Precision (DOP) : 0.000000
Lens min focal length: 0.000000 mm
Lens max focal length: 0.000000 mm
Lens f-stop min : f/0.0
Lens f-stop max : f/0.0
Lens make :
Lens model :
Focal plane XRes : 0.000000
Focal plane YRes : 0.000000
==84545==
==84545== HEAP SUMMARY:
==84545== in use at exit: 26,750 bytes in 195 blocks
==84545== total heap usage: 336 allocs, 141 frees, 930,484 bytes allocated
==84545==
==84545== 148 (80 direct, 68 indirect) bytes in 1 blocks are definitely lost in loss record 44 of 68
==84545== at 0x10000CEBB: malloc (in /usr/local/Cellar/valgrind/3.11.0/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==84545== by 0x1002B08B6: __Balloc_D2A (in /usr/lib/system/libsystem_c.dylib)
==84545== by 0x1002B11FF: __d2b_D2A (in /usr/lib/system/libsystem_c.dylib)
==84545== by 0x1002AD857: __dtoa (in /usr/lib/system/libsystem_c.dylib)
==84545== by 0x1002D63DE: __vfprintf (in /usr/lib/system/libsystem_c.dylib)
==84545== by 0x1002FF6C0: __v2printf (in /usr/lib/system/libsystem_c.dylib)
==84545== by 0x1002D5381: vfprintf_l (in /usr/lib/system/libsystem_c.dylib)
==84545== by 0x1002D321B: printf (in /usr/lib/system/libsystem_c.dylib)
==84545== by 0x1000043D7: main (in ./demo)
==84545==
==84545== LEAK SUMMARY:
==84545== definitely lost: 80 bytes in 1 blocks
==84545== indirectly lost: 68 bytes in 2 blocks
==84545== possibly lost: 0 bytes in 0 blocks
==84545== still reachable: 0 bytes in 0 blocks
==84545== suppressed: 26,602 bytes in 192 blocks
==84545==
==84545== For counts of detected and suppressed errors, rerun with: -v
==84545== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 19 from 19)
Please advise how to fix this bug. Thanks.
The JPG parsing is sometimes failing, when the file does not end by EOS (it is possible to end in 0xFF added as padding to EOS).
When I try to use this image I get a segfault: https://drive.google.com/file/d/0B5ISHWiseP1oSVpJS1o2TllnOE0/view?usp=sharing
I can trace the error to the point where it is trying to set the ISOSpeedRatings (line 613 in exif.cpp), but I am unsure of the cause. Clearly though, result.val_short() is an empty vector, and so accessing the front() element is what is causing hte segfault
There are some strange binary chars in GPS Latitude and GPS Longitude
When I open it in vim:
GPS Latitude : 0.000000 deg (0.000000 deg, 0.000000 min, 0.000000 sec �^@)
GPS Longitude : 0.000000 deg (0.000000 deg, 0.000000 min, 0.000000 sec ^@�)
Is there any special reason for these chars? Or can it be removed?
I know the file formats are very different, but support for reading metadata from Jpeg2000 files would be really useful!
Hello,
Attached are 2 files with non-zero exposure bias value. DSC_5644 is +0.3 EV and DSC02268 is -1.3EV. Easyexif reports 0 for both images.
In fact the exposure bias value is not read at all, as the expected format is 5, but the reported format is 10. I've tried to force-read the tag as format 5, but it crashed.
Thanks for your help.
I Try to complie in my eclipse project , Couldnot complie it.
Any suggestion??
I looked at implementation of parseFrom method, here is piece of code:
for (offs = 0; offs < len - 1; offs++)
if (buf[offs] == 0xFF && buf[offs + 1] == 0xE1) break;
As I understand, it searches exif marker. Is it correct? AS I understand, we should skip internal data of markers, and here we should find length of marker segment, if it is not exif then we should skip it (otherwise we can accidentially find that marker data from different marker segment). Am I right?
See https://farm3.staticflickr.com/2912/13981352255_164ce008dc_o_d.jpg for example.
Hi,
Thank you for the great EXIF lib, it is exactly what I needed: small and working.
I just needed some more fields very important for my Structure-from-Motion app, like "Focal plane resolution" and GPS precision, which were very easy to add. If you think it's worthy, please find included the link to the patch.
https://drive.google.com/file/d/0B8bb0qT4PvT8OFZOdkdCdlkwQkE/view?usp=sharing
Cheers!
Hi Mayank
Thanks for the nice and lightweigtht exif library!
I just run into the situation where a 'std::length_error' on string resize was thrown. It boils down to the following line in exif.cpp:350
if (result.val_string()[result.val_string().length() - 1] == '\0') {
result.val_string().resize(result.val_string().length() - 1);
}
The length of val_string() is not guaranteed to be > 0 and in my case it happend to be empty (resulting in an invalid memory access). The fix is easy:
if (!result.val_string().empty() && result.val_string()[result.val_string().length() - 1] == '\0') {
result.val_string().resize(result.val_string().length() - 1);
}
Cheers & have a nice day
Alex
Just a feature request.
Is it possible to extract ICC profile data ?
Hi,
I am running some experiments for AFLAPI and it has found that segmentation fault and heap-buffer-overflow occured in easyexif::EXIFInfo::parseFromEXIFSegment at exif.cpp:811 when parse a crafted (also bad) jpg.
Environment: Ubuntu 18.04 + clang 6.0.0
Pocs here:
pocs.zip
To reproduce:
$ clang++ -fsanitize=address -c exif.cpp
$ clang++ -fsanitize=address demo.cpp exif.o -o demo
$ ./demo segv.jpg
$ ./demo heap-overflow.jpg
For SEGV, ASAN says:
$ ./demo segv.jpg
AddressSanitizer:DEADLYSIGNAL
=================================================================
==65083==ERROR: AddressSanitizer: SEGV on unknown address 0x62500040146e (pc 0x0000005279df bp 0x7fff0d4c6370 sp 0x7fff0d4c6320 T0)
==65083==The signal is caused by a READ memory access.
#0 0x5279de in unsigned int (anonymous namespace)::parse<unsigned int, false>(unsigned char const*) (/home/ubuntu/some_c_test/easyexif/demo+0x5279de)
#1 0x527c44 in (anonymous namespace)::Rational (anonymous namespace)::parse<(anonymous namespace)::Rational, false>(unsigned char const*) (/home/ubuntu/some_c_test/easyexif/demo+0x527c44)
#2 0x51f78e in (anonymous namespace)::Rational (anonymous namespace)::parse_value<(anonymous namespace)::Rational>(unsigned char const*, bool) (/home/ubuntu/some_c_test/easyexif/demo+0x51f78e)
#3 0x51d100 in easyexif::EXIFInfo::parseFromEXIFSegment(unsigned char const*, unsigned int) (/home/ubuntu/some_c_test/easyexif/demo+0x51d100)
#4 0x518fb1 in easyexif::EXIFInfo::parseFrom(unsigned char const*, unsigned int) (/home/ubuntu/some_c_test/easyexif/demo+0x518fb1)
#5 0x51773c in main (/home/ubuntu/some_c_test/easyexif/demo+0x51773c)
#6 0x7f3e576d9c86 in __libc_start_main /build/glibc-CVJwZb/glibc-2.27/csu/../csu/libc-start.c:310
#7 0x41abb9 in _start (/home/ubuntu/some_c_test/easyexif/demo+0x41abb9)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (/home/ubuntu/some_c_test/easyexif/demo+0x5279de) in unsigned int (anonymous namespace)::parse<unsigned int, false>(unsigned char const*)
==65083==ABORTING
For heap-buffer-overflow, ASAN says:
$ ./demo heap-overflow.jpg
=================================================================
==65663==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x618000009320 at pc 0x0000005279db bp 0x7ffec71cfff0 sp 0x7ffec71cffe8
READ of size 1 at 0x618000009320 thread T0
#0 0x5279da in unsigned int (anonymous namespace)::parse<unsigned int, false>(unsigned char const*) (/home/ubuntu/some_c_test/easyexif/demo+0x5279da)
#1 0x527c44 in (anonymous namespace)::Rational (anonymous namespace)::parse<(anonymous namespace)::Rational, false>(unsigned char const*) (/home/ubuntu/some_c_test/easyexif/demo+0x527c44)
#2 0x51f78e in (anonymous namespace)::Rational (anonymous namespace)::parse_value<(anonymous namespace)::Rational>(unsigned char const*, bool) (/home/ubuntu/some_c_test/easyexif/demo+0x51f78e)
#3 0x51dd09 in easyexif::EXIFInfo::parseFromEXIFSegment(unsigned char const*, unsigned int) (/home/ubuntu/some_c_test/easyexif/demo+0x51dd09)
#4 0x518fb1 in easyexif::EXIFInfo::parseFrom(unsigned char const*, unsigned int) (/home/ubuntu/some_c_test/easyexif/demo+0x518fb1)
#5 0x51773c in main (/home/ubuntu/some_c_test/easyexif/demo+0x51773c)
#6 0x7f394f16dc86 in __libc_start_main /build/glibc-CVJwZb/glibc-2.27/csu/../csu/libc-start.c:310
#7 0x41abb9 in _start (/home/ubuntu/some_c_test/easyexif/demo+0x41abb9)
Address 0x618000009320 is a wild pointer.
SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/ubuntu/some_c_test/easyexif/demo+0x5279da) in unsigned int (anonymous namespace)::parse<unsigned int, false>(unsigned char const*)
Shadow bytes around the buggy address:
0x0c307fff9210: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c307fff9220: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c307fff9230: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c307fff9240: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c307fff9250: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c307fff9260: fa fa fa fa[fa]fa fa fa fa fa fa fa fa fa fa fa
0x0c307fff9270: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c307fff9280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c307fff9290: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c307fff92a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c307fff92b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==65663==ABORTING
Exif info can also exist in TIFF images. This is maybe not so relevant or popular because it's not widely-used.
But nevertheless one question:
Do you know if there is a huge difference between analysing Exif and JPEG and TIFF? Could one adapt or extend exif.cpp easily to also handle Exif from TIFF?
I want to read fujifilm exif data, can this library do it?
First up: Thanks for this project!
Tried the demo on a few of my own images from my phone and it chocked on the third one I tried. The reason was the end marker sanity check (line 427 in exif.cpp). I checked the image file in a hex editor and the last 100 kB or so are zero (as you indicate in your comments), but the zero padding does indeed not start with the (required?) 0xFFD9. The image can be viewed on the phone as well as when clicking on it in dolphin. So, I think I have an image file, which is somehow corrupt or at least not formally correct, but somehow seems to work.
I removed the sanity check and my images are now correctly parsed. I also successfully executed your tests without the sanity check.
Since we are in principle only interested in the metadata-part, do we real care about the image itself?
👋 Hello, we've received a report for a potential medium severity security issue in your repository.
1️⃣ Visit https://huntr.dev/bounties/1-other-mayanklahiri/easyexif for more advisory information.
2️⃣ Sign-up to validate or speak to the researcher for more assistance.
3️⃣ Propose a patch or outsource it to our community.
Join us on our Discord and a member of our team will be happy to help! 🤗
Speak to a member of our team: @JamieSlome
This issue was automatically generated by huntr.dev - a bug bounty board for securing open source code.
Hello there ,
I've been wrting some fuzzing test scripts and a mutated jpg file generated has lead to a SEGV in
easyexif::EXIFInfo::parseEXIFSubIFD(unsigned char const*, unsigned int, unsigned int) exif.cpp:910
, caused by a invalid memory access in :Rational::operator double (this=0x0) at exif.cpp:60
, the ASAN details are as follows:
$ ./demo ./crash14.jpg
AddressSanitizer:DEADLYSIGNAL
=================================================================
==1702445==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000004 (pc 0x55a757cd7835 bp 0x7ffc8f1535c0 sp 0x7ffc8f1535b0 T0)
==1702445==The signal is caused by a READ memory access.
==1702445==Hint: address points to the zero page.
#0 0x55a757cd7835 in operator double /mnt/c/Users/Orrr/Desktop/caveman_fuzzer/caveman_fuzzer/easyexif-master/easyexif-master/exif.cpp:60
#1 0x55a757cdbda2 in easyexif::EXIFInfo::parseEXIFSubIFD(unsigned char const*, unsigned int, unsigned int) /mnt/c/Users/Orrr/Desktop/caveman_fuzzer/caveman_fuzzer/easyexif-master/easyexif-master/exif.cpp:910
#2 0x55a757cd973f in easyexif::EXIFInfo::parseFromEXIFSegment(unsigned char const*, unsigned int) /mnt/c/Users/Orrr/Desktop/caveman_fuzzer/caveman_fuzzer/easyexif-master/easyexif-master/exif.cpp:581
#3 0x55a757cd93bc in easyexif::EXIFInfo::parseFrom(unsigned char const*, unsigned int) /mnt/c/Users/Orrr/Desktop/caveman_fuzzer/caveman_fuzzer/easyexif-master/easyexif-master/exif.cpp:519
#4 0x55a757ce9b5c in main /mnt/c/Users/Orrr/Desktop/caveman_fuzzer/caveman_fuzzer/easyexif-master/easyexif-master/demo.cpp:31
#5 0x7f40c6c93d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#6 0x7f40c6c93e3f in __libc_start_main_impl ../csu/libc-start.c:392
#7 0x55a757cd7724 in _start (/mnt/c/Users/Orrr/Desktop/caveman_fuzzer/caveman_fuzzer/easyexif-master/easyexif-master/demo+0x3724)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /mnt/c/Users/Orrr/Desktop/caveman_fuzzer/caveman_fuzzer/easyexif-master/easyexif-master/exif.cpp:60 in operator double
==1702445==ABORTING
env:
g++ (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
Ubuntu 22.04.4 LTS
5.15.153.1-microsoft-standard-WSL2
To reproduce this :
makefile:
CXX=g++
CXXFLAGS=-fsanitize=address -ggdb
all: demo
exif.o: exif.cpp
$(CXX) $(CXXFLAGS) -c exif.cpp
demo: exif.o demo.cpp
$(CXX) $(CXXFLAGS) -o demo exif.o demo.cpp
clean:
rm -f *.o demo demo.exe
$ make
$ ./demo crash14.jpg
below are some gdb info for this SEGV
────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]─────────────────────────────
*RAX 0x0
*RBX 0x7fffffffcc90 —▸ 0x7fffffffcd10 ◂— 0x41b58ab3
*RCX 0x7
*RDX 0x0
*RDI 0x0
*RSI 0x0
*R8 0x7fffffffcc30 —▸ 0x3ac0005a20f ◂— 0x0
R9 0x0
*R10 0x7ffff44ea900 ◂— 0x0
*R11 0x7fffff7ff000 ◂— 0x7fffff7ff000
*R12 0x7fffffffcc10 ◂— 0x41b58ab3
*R13 0xffffffff982 ◂— 0x0
*R14 0x7fffffffcc10 ◂— 0x41b58ab3
R15 0x7fffffffce30 ◂— 0x41b58ab3
*RBP 0x7fffffffcbd0 —▸ 0x7fffffffccb0 —▸ 0x7fffffffcdb0 —▸ 0x7fffffffcdf0 —▸ 0x7fffffffd460 ◂— ...
*RSP 0x7fffffffcbc0 ◂— 0x0
*RIP 0x555555557835 ((anonymous namespace)::Rational::operator double() const+75) ◂— mov eax, dword ptr [rax + 4]
─────────────────────────────────────[ DISASM / x86-64 / set emulate on ]──────────────────────────────────────
► 0x555555557835 <(anonymous namespace)::Rational::operator double() const+75> mov eax, dword ptr [rax + 4]
0x555555557838 <(anonymous namespace)::Rational::operator double() const+78> test eax, eax
0x55555555783a <(anonymous namespace)::Rational::operator double() const+80> jne 555555557845h <(anonymous namespace)::Rational::operator double() const+91>
↓
0x555555557845 <(anonymous namespace)::Rational::operator double() const+91> mov rax, qword ptr [rbp - 8]
0x555555557849 <(anonymous namespace)::Rational::operator double() const+95> mov rdx, rax
0x55555555784c <(anonymous namespace)::Rational::operator double() const+98> shr rdx, 3
0x555555557850 <(anonymous namespace)::Rational::operator double() const+102> add rdx, 7fff8000h
0x555555557857 <(anonymous namespace)::Rational::operator double() const+109> movzx edx, byte ptr [rdx]
0x55555555785a <(anonymous namespace)::Rational::operator double() const+112> test dl, dl
0x55555555785c <(anonymous namespace)::Rational::operator double() const+114> setne sil
0x555555557860 <(anonymous namespace)::Rational::operator double() const+118> mov rcx, rax
───────────────────────────────────────────────[ SOURCE (CODE) ]───────────────────────────────────────────────
In file: /mnt/c/Users/Orrr/Desktop/caveman_fuzzer/caveman_fuzzer/easyexif-master/easyexif-master/exif.cpp
55 struct Rational {
56 uint32_t numerator = 0;
57 uint32_t denominator = 0;
58
59 operator double() const {
► 60 if (denominator < 1e-20) {
61 return 0;
62 }
Is there a reason why demo should be in the repository?
It's linux only, could be compiled so it won't run on other machine and it is changed in nearly every commit which runs test.sh.
IMHO it should be just removed (expecially since running make
takes like 2 seconds even on my weak netbook).
Hi,
I'm about to pack your project for Guix and I need some clarification for the license you mentioned in README (BSD) and in LICENSE file (all right reserved).
If it's BSD, which type of them?
I'm creating a photo organizer and used your program to do so. It works perfectly thank you and huge kudos. Now that jpeg is out of the way I would want to support png and avi (video) do you know if I can do something to support it? some modification to the code, or some other software written in c++ ?
Thank you !
/easyexif/exif.cpp:467:61: warning: implicit conversion loses integer precision: 'size_type' (aka 'unsigned long') to 'unsigned int' [-Wshorten-64-to-32]
/easyexif/exif.cpp:709:22: warning: implicit conversion loses integer precision: 'size_type' (aka 'unsigned long') to 'int' [-Wshorten-64-to-32]
clang -v
Apple LLVM version 8.0.0 (clang-800.0.38)
Target: x86_64-apple-darwin15.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
xcodebuild -version
Xcode 8.0
Build version 8A218a
Hello Sir,
When I try to get the image direction or Direction in degrees I am getting always zero.
For your reference I am attaching one image with direction of
29309/92 or 318.58 Degrees
But
easyexif library is returning zero.
for testing http://www.pic2map.com/
Thanks
Naresh
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.