OLD | NEW |
---|---|
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome_elf/nt_registry/nt_registry.h" | 5 #include "chrome_elf/nt_registry/nt_registry.h" |
6 | 6 |
7 #include <assert.h> | 7 #include <assert.h> |
8 #include <stdlib.h> | 8 #include <stdlib.h> |
9 | 9 |
10 namespace { | 10 namespace { |
(...skipping 524 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
535 out_base->push_back(L'\\'); | 535 out_base->push_back(L'\\'); |
536 } | 536 } |
537 subkeys->erase(subkeys->begin(), subkeys->begin() + num_base_tokens); | 537 subkeys->erase(subkeys->begin(), subkeys->begin() + num_base_tokens); |
538 } else { | 538 } else { |
539 out_base->assign(converted_root); | 539 out_base->assign(converted_root); |
540 } | 540 } |
541 | 541 |
542 return true; | 542 return true; |
543 } | 543 } |
544 | 544 |
545 // String safety. | |
546 // - NOTE: only working with wchar_t here. | |
547 // - Also ensures the content of |value_bytes| is at least a terminator. | |
548 // - Pass "true" for |multi| for MULTISZ. | |
549 void EnsureTerminatedSZ(std::vector<BYTE>* value_bytes, bool multi) { | |
550 DWORD terminator_size = sizeof(wchar_t); | |
551 | |
552 if (multi) | |
553 terminator_size = 2 * sizeof(wchar_t); | |
554 | |
555 // Ensure content is at least the size of a terminator. | |
556 for (size_t i = value_bytes->size(); i < terminator_size; i++) | |
grt (UTC plus 2)
2017/07/20 05:22:53
if (value_bytes->size() < terminator_size) {
v
penny
2017/07/20 18:38:37
Done. <sigh> Thank you for your 1337 c++ skillz
| |
557 value_bytes->push_back(0); | |
558 | |
559 // Sanity check content size based on character size. | |
560 DWORD modulo = value_bytes->size() % sizeof(wchar_t); | |
561 while (modulo) { | |
grt (UTC plus 2)
2017/07/20 05:22:53
value_bytes->insert(value_bytes->end(), modulo, 0)
penny
2017/07/20 18:38:37
Done.
| |
562 value_bytes->push_back(0); | |
563 modulo--; | |
564 } | |
565 | |
566 // Now finally check for trailing terminator. | |
567 bool terminated = true; | |
568 size_t last_element = value_bytes->size() - 1; | |
569 for (size_t i = 0; i < terminator_size; i++) { | |
570 if ((*value_bytes)[last_element - i] != 0) { | |
571 terminated = false; | |
572 break; | |
573 } | |
574 } | |
575 | |
576 if (terminated) | |
577 return; | |
578 | |
579 // Append a full terminator to be safe. | |
580 for (size_t i = 0; i < terminator_size; i++) | |
grt (UTC plus 2)
2017/07/20 05:22:53
value_bytes->insert(value_bytes->end(), terminator
penny
2017/07/20 18:38:37
Done.
| |
581 value_bytes->push_back(0); | |
582 | |
583 return; | |
584 } | |
585 | |
545 //------------------------------------------------------------------------------ | 586 //------------------------------------------------------------------------------ |
546 // Misc wrapper functions - LOCAL | 587 // Misc wrapper functions - LOCAL |
547 //------------------------------------------------------------------------------ | 588 //------------------------------------------------------------------------------ |
548 | 589 |
549 NTSTATUS CreateKeyWrapper(const std::wstring& key_path, | 590 NTSTATUS CreateKeyWrapper(const std::wstring& key_path, |
550 ACCESS_MASK access, | 591 ACCESS_MASK access, |
551 HANDLE* out_handle, | 592 HANDLE* out_handle, |
552 ULONG* create_or_open OPTIONAL) { | 593 ULONG* create_or_open OPTIONAL) { |
553 UNICODE_STRING key_path_uni = {}; | 594 UNICODE_STRING key_path_uni = {}; |
554 g_rtl_init_unicode_string(&key_path_uni, key_path.c_str()); | 595 g_rtl_init_unicode_string(&key_path_uni, key_path.c_str()); |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
742 g_nt_close(key); | 783 g_nt_close(key); |
743 } | 784 } |
744 | 785 |
745 //------------------------------------------------------------------------------ | 786 //------------------------------------------------------------------------------ |
746 // Getter functions | 787 // Getter functions |
747 //------------------------------------------------------------------------------ | 788 //------------------------------------------------------------------------------ |
748 | 789 |
749 bool QueryRegKeyValue(HANDLE key, | 790 bool QueryRegKeyValue(HANDLE key, |
750 const wchar_t* value_name, | 791 const wchar_t* value_name, |
751 ULONG* out_type, | 792 ULONG* out_type, |
752 BYTE** out_buffer, | 793 std::vector<BYTE>* out_buffer) { |
753 DWORD* out_size) { | |
754 if (!g_initialized) | 794 if (!g_initialized) |
755 InitNativeRegApi(); | 795 InitNativeRegApi(); |
756 | 796 |
757 NTSTATUS ntstatus = STATUS_UNSUCCESSFUL; | 797 NTSTATUS ntstatus = STATUS_UNSUCCESSFUL; |
758 UNICODE_STRING value_uni = {}; | 798 UNICODE_STRING value_uni = {}; |
759 g_rtl_init_unicode_string(&value_uni, value_name); | 799 g_rtl_init_unicode_string(&value_uni, value_name); |
760 DWORD size_needed = 0; | 800 DWORD size_needed = 0; |
761 bool success = false; | 801 bool success = false; |
762 | 802 |
763 // First call to find out how much room we need for the value! | 803 // First call to find out how much room we need for the value! |
764 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation, | 804 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation, |
765 nullptr, 0, &size_needed); | 805 nullptr, 0, &size_needed); |
766 if (ntstatus != STATUS_BUFFER_TOO_SMALL) | 806 if (ntstatus != STATUS_BUFFER_TOO_SMALL) |
767 return false; | 807 return false; |
768 | 808 |
769 KEY_VALUE_FULL_INFORMATION* value_info = | 809 KEY_VALUE_FULL_INFORMATION* value_info = |
770 reinterpret_cast<KEY_VALUE_FULL_INFORMATION*>(new BYTE[size_needed]); | 810 reinterpret_cast<KEY_VALUE_FULL_INFORMATION*>(new BYTE[size_needed]); |
771 | 811 |
772 // Second call to get the value. | 812 // Second call to get the value. |
773 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation, | 813 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation, |
774 value_info, size_needed, &size_needed); | 814 value_info, size_needed, &size_needed); |
775 if (NT_SUCCESS(ntstatus)) { | 815 if (NT_SUCCESS(ntstatus)) { |
776 *out_type = value_info->Type; | 816 *out_type = value_info->Type; |
777 *out_size = value_info->DataLength; | 817 DWORD data_size = value_info->DataLength; |
778 *out_buffer = new BYTE[*out_size]; | 818 out_buffer->clear(); |
grt (UTC plus 2)
2017/07/20 05:22:53
nit: by using assign() below, clear() is only need
penny
2017/07/20 18:38:36
Done.
| |
779 ::memcpy(*out_buffer, | 819 if (data_size) { |
780 (reinterpret_cast<BYTE*>(value_info) + value_info->DataOffset), | 820 // Move the data into |out_buffer| vector. |
781 *out_size); | 821 BYTE* data = reinterpret_cast<BYTE*>(value_info) + value_info->DataOffset; |
822 for (size_t i = 0; i < data_size; i++) | |
grt (UTC plus 2)
2017/07/20 05:22:53
out_buffer->assign(data, data + data_size);
penny
2017/07/20 18:38:37
assign. thank you.
| |
823 out_buffer->push_back(data[i]); | |
824 } | |
782 success = true; | 825 success = true; |
783 } | 826 } |
784 | 827 |
785 delete[] value_info; | 828 delete[] value_info; |
786 return success; | 829 return success; |
787 } | 830 } |
788 | 831 |
789 // wrapper function | 832 // wrapper function |
790 bool QueryRegValueDWORD(HANDLE key, | 833 bool QueryRegValueDWORD(HANDLE key, |
791 const wchar_t* value_name, | 834 const wchar_t* value_name, |
792 DWORD* out_dword) { | 835 DWORD* out_dword) { |
793 ULONG type = REG_NONE; | 836 ULONG type = REG_NONE; |
794 BYTE* value_bytes = nullptr; | 837 std::vector<BYTE> value_bytes; |
795 DWORD ret_size = 0; | |
796 | 838 |
797 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes, &ret_size) || | 839 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes) || |
798 type != REG_DWORD) | 840 type != REG_DWORD) { |
841 return false; | |
842 } | |
843 | |
844 if (value_bytes.size() < sizeof(*out_dword)) | |
799 return false; | 845 return false; |
800 | 846 |
801 *out_dword = *(reinterpret_cast<DWORD*>(value_bytes)); | 847 *out_dword = *(reinterpret_cast<DWORD*>(value_bytes.data())); |
802 | 848 |
803 delete[] value_bytes; | |
804 return true; | 849 return true; |
805 } | 850 } |
806 | 851 |
807 // wrapper function | 852 // wrapper function |
808 bool QueryRegValueDWORD(ROOT_KEY root, | 853 bool QueryRegValueDWORD(ROOT_KEY root, |
809 WOW64_OVERRIDE wow64_override, | 854 WOW64_OVERRIDE wow64_override, |
810 const wchar_t* key_path, | 855 const wchar_t* key_path, |
811 const wchar_t* value_name, | 856 const wchar_t* value_name, |
812 DWORD* out_dword) { | 857 DWORD* out_dword) { |
813 HANDLE key = INVALID_HANDLE_VALUE; | 858 HANDLE key = INVALID_HANDLE_VALUE; |
814 | 859 |
815 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL)) | 860 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL)) |
816 return false; | 861 return false; |
817 | 862 |
818 if (!QueryRegValueDWORD(key, value_name, out_dword)) { | 863 if (!QueryRegValueDWORD(key, value_name, out_dword)) { |
819 CloseRegKey(key); | 864 CloseRegKey(key); |
820 return false; | 865 return false; |
821 } | 866 } |
822 | 867 |
823 CloseRegKey(key); | 868 CloseRegKey(key); |
824 return true; | 869 return true; |
825 } | 870 } |
826 | 871 |
827 // wrapper function | 872 // wrapper function |
828 bool QueryRegValueSZ(HANDLE key, | 873 bool QueryRegValueSZ(HANDLE key, |
829 const wchar_t* value_name, | 874 const wchar_t* value_name, |
830 std::wstring* out_sz) { | 875 std::wstring* out_sz) { |
831 BYTE* value_bytes = nullptr; | 876 std::vector<BYTE> value_bytes; |
832 DWORD ret_size = 0; | |
833 ULONG type = REG_NONE; | 877 ULONG type = REG_NONE; |
834 | 878 |
835 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes, &ret_size) || | 879 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes) || |
836 type != REG_SZ) | 880 (type != REG_SZ && type != REG_EXPAND_SZ)) { |
837 return false; | 881 return false; |
882 } | |
838 | 883 |
839 *out_sz = reinterpret_cast<wchar_t*>(value_bytes); | 884 EnsureTerminatedSZ(&value_bytes, false); |
840 | 885 |
841 delete[] value_bytes; | 886 *out_sz = reinterpret_cast<wchar_t*>(value_bytes.data()); |
grt (UTC plus 2)
2017/07/20 05:22:53
should this preserve embedded nulls? if yes, use o
penny
2017/07/20 18:38:37
I never expected the result of the QueryRegValueSZ
grt (UTC plus 2)
2017/07/21 08:09:00
Sounds reasonable to me. Please document this beha
penny
2017/07/25 18:30:47
Done.
| |
887 | |
842 return true; | 888 return true; |
843 } | 889 } |
844 | 890 |
845 // wrapper function | 891 // wrapper function |
846 bool QueryRegValueSZ(ROOT_KEY root, | 892 bool QueryRegValueSZ(ROOT_KEY root, |
847 WOW64_OVERRIDE wow64_override, | 893 WOW64_OVERRIDE wow64_override, |
848 const wchar_t* key_path, | 894 const wchar_t* key_path, |
849 const wchar_t* value_name, | 895 const wchar_t* value_name, |
850 std::wstring* out_sz) { | 896 std::wstring* out_sz) { |
851 HANDLE key = INVALID_HANDLE_VALUE; | 897 HANDLE key = INVALID_HANDLE_VALUE; |
852 | 898 |
853 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL)) | 899 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | wow64_override, &key, NULL)) |
854 return false; | 900 return false; |
855 | 901 |
856 if (!QueryRegValueSZ(key, value_name, out_sz)) { | 902 if (!QueryRegValueSZ(key, value_name, out_sz)) { |
857 CloseRegKey(key); | 903 CloseRegKey(key); |
858 return false; | 904 return false; |
859 } | 905 } |
860 | 906 |
861 CloseRegKey(key); | 907 CloseRegKey(key); |
862 return true; | 908 return true; |
863 } | 909 } |
864 | 910 |
865 // wrapper function | 911 // wrapper function |
866 bool QueryRegValueMULTISZ(HANDLE key, | 912 bool QueryRegValueMULTISZ(HANDLE key, |
867 const wchar_t* value_name, | 913 const wchar_t* value_name, |
868 std::vector<std::wstring>* out_multi_sz) { | 914 std::vector<std::wstring>* out_multi_sz) { |
869 BYTE* value_bytes = nullptr; | 915 std::vector<BYTE> value_bytes; |
870 DWORD ret_size = 0; | |
871 ULONG type = REG_NONE; | 916 ULONG type = REG_NONE; |
872 | 917 |
873 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes, &ret_size) || | 918 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes) || |
874 type != REG_MULTI_SZ) | 919 type != REG_MULTI_SZ) { |
875 return false; | 920 return false; |
921 } | |
876 | 922 |
877 // Make sure the vector is empty to start. | 923 EnsureTerminatedSZ(&value_bytes, true); |
878 (*out_multi_sz).resize(0); | |
879 | 924 |
880 wchar_t* pointer = reinterpret_cast<wchar_t*>(value_bytes); | 925 // Make sure the out vector is empty to start. |
926 (*out_multi_sz).clear(); | |
927 | |
928 wchar_t* pointer = reinterpret_cast<wchar_t*>(value_bytes.data()); | |
881 std::wstring temp = pointer; | 929 std::wstring temp = pointer; |
robertshield
2017/07/20 17:14:04
Won't this truncate any characters after the first
penny
2017/07/20 18:38:37
No. It merely creates a new wstring object, and c
| |
882 // Loop. Each string is separated by '\0'. Another '\0' at very end (so 2 in | 930 // Loop. Each string is separated by '\0'. Another '\0' at very end (so 2 in |
883 // a row). | 931 // a row). |
884 while (temp.length() != 0) { | 932 while (temp.length() != 0) { |
grt (UTC plus 2)
2017/07/20 05:22:53
nit: !temp.empty()
penny
2017/07/20 18:38:37
I wasn't entirely sure whether an empty string (""
grt (UTC plus 2)
2017/07/21 08:09:00
The spec more-or-less says that a std::basic_strin
penny
2017/07/25 18:30:47
Done. Clear as mud!
| |
885 (*out_multi_sz).push_back(temp); | 933 (*out_multi_sz).push_back(temp); |
grt (UTC plus 2)
2017/07/20 05:22:53
nit: avoid making another copy of |temp| with:
penny
2017/07/20 18:38:36
Done. I didn't even think push_back could take th
grt (UTC plus 2)
2017/07/21 08:09:00
I didn't know either -- I just figured something l
| |
886 | 934 |
887 pointer += temp.length() + 1; | 935 pointer += temp.length() + 1; |
888 temp = pointer; | 936 temp = pointer; |
889 } | 937 } |
890 | 938 |
891 // Handle the case of "empty multi_sz". | |
892 if (out_multi_sz->size() == 0) | |
893 out_multi_sz->push_back(L""); | |
894 | |
895 delete[] value_bytes; | |
896 return true; | 939 return true; |
897 } | 940 } |
898 | 941 |
899 // wrapper function | 942 // wrapper function |
900 bool QueryRegValueMULTISZ(ROOT_KEY root, | 943 bool QueryRegValueMULTISZ(ROOT_KEY root, |
901 WOW64_OVERRIDE wow64_override, | 944 WOW64_OVERRIDE wow64_override, |
902 const wchar_t* key_path, | 945 const wchar_t* key_path, |
903 const wchar_t* value_name, | 946 const wchar_t* value_name, |
904 std::vector<std::wstring>* out_multi_sz) { | 947 std::vector<std::wstring>* out_multi_sz) { |
905 HANDLE key = INVALID_HANDLE_VALUE; | 948 HANDLE key = INVALID_HANDLE_VALUE; |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1089 if (!g_initialized) | 1132 if (!g_initialized) |
1090 InitNativeRegApi(); | 1133 InitNativeRegApi(); |
1091 | 1134 |
1092 if (root == HKCU || (root == AUTO && !g_system_install)) | 1135 if (root == HKCU || (root == AUTO && !g_system_install)) |
1093 return g_HKCU_override; | 1136 return g_HKCU_override; |
1094 | 1137 |
1095 return g_HKLM_override; | 1138 return g_HKLM_override; |
1096 } | 1139 } |
1097 | 1140 |
1098 }; // namespace nt | 1141 }; // namespace nt |
OLD | NEW |